Friday, August 17, 2018

How to Start and Access Jenkins in Windows?

Today we would be discussing how to start & access Jenkins in Windows systems. It won't take a minute to get it working. After reading this, one would be able to answer below questions:

Q1: How to start & access Jenkins in Windows using default port i.e. 8080?
Q2: How to start Jenkins on the desired port in Windows?
Q3: What is the default credentials for Jenkins after installation? 

Let's get started.
Step1: Download the latest Jenkins WAR(jenkins.war) from the official site.
Step2: Run the below commands at Command prompt
# run at default port i.e. 8080
java -jar jenkins.war
# run at desired port, use http or https
java -jar jenkins.war --httpPort=8081
java -jar jenkins.war --httpsPort=8081
Step3: Access Jenkins
If you are running the Jenkins in your local environment then hit http://localhost:8081/ in your browser. You would see the Jenkins Home Page screen:
At the top right corner, you will see the option for login & sign up. Let's login using the default admin account. Click on 'log in' link to navigate to the Jenkins Log In Page:

You must be wondering from where we would get the username & password.
username: admin
password: .jenkins/secrets/initialAdminPassword  [Jenkins home directory=$user.home/.jenkins]
Jenkins After Sign In 

Hoping that now you have running Jenkins. Start exploring it. Happy Learning!! :-)

Reference:

[1]: https://wiki.jenkins.io/display/JENKINS/Starting+and+Accessing+Jenkins

Monday, June 4, 2018

How to debug errors while using Spring Security module?

If you have ever used Spring Security module for authentication or authorization then you already know the pain while debugging the errors that has encountered while customizing the Spring Web Security i.e. by using annotation like @EnableWebSecurity to customize the Spring Security configuration by extending the WebSecurityConfigurerAdapter base class and overriding individual methods.  Today we would be discussing three ways that would help us to debug Spring Security related error nicely as we will be logging more detailed information in debug mode that would in turn help us in resolving the issues.

Disclaimer: I have tried these methods in Spring Boot and it worked like charm.

1. Turn On the Debug Level log for Spring Framework Web & Security module

As per your convenience, set the below properties in application.yml or application.properties file.
logging.level.org.springframework.security=DEBUG
logging.level.org.springframework.web=DEBUG

2. More concerned about Filter Chain

If one is more concerned about Filter Chain related log information then one could also log in more granular level i.e. logging the FilterChainProxy class.
#application.yml
logging:
  level:
     org:
       springframework:
         security:
          web:
            FilterChainProxy: DEBUG
   
or #application.properties
logging.level.org.springframework.web.FilterChainProxy=Debug   

3. Additional Filter logs specific to a particular request 

If one would like to see what different filters are applied to particular request then one could also set the debug flag to true in @EnableWebSecurity annotation.
@EnableWebSecurity(debug = true)
For reference, see the logs
************************************************************

Request received for GET '/oauth/token':

org.apache.catalina.connector.RequestFacade@2a27c195

servletPath:/oauth/token
pathInfo:null
headers: 
host: localhost:8060
connection: keep-alive
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
cookie: _ga=GA1.1.46570692.1519211292; JSESSIONID=2BDB6DDBCD404F240AF3DB3331C25BF4


Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  LogoutFilter
  BasicAuthenticationFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]


************************************************************
One should always keep one thing in mind that depending on the configuration we state in our security configuration class, the order and number of the filters in the filter chain may differ. Let's understand it by an example: http.anonymous().disable() in the class extending WebSecurityConfigurerAdapter class would exclude  AnonymousAuthenticationFilter from the filter chain.

Happy Learning!! Hoping that now you would play with these debug level log and resolve your Spring Security related errors in lesser time. 

Thursday, May 24, 2018

How to install & configure the AWS CLI on Windows system

One can easily use AWS Management Console to manage their AWS services but if one wants to access & manage their AWS services programmatically then one could install & configure AWS CLI. Today we would be discussing, how to install & configure AWS CLI in Windows systems.
Table Of Content:
1. Introductions
2. Installing the AWS CLI
3. Configuring the AWS CLI
4. Conclusion

Wednesday, May 23, 2018

JBoss Deployment Error: java.lang.LinkageError: loader constraint violation

Getting deployment errors are inevitable. One can't escape from it. Recently I have got a deployment error i.e. java.lang.LinkageError: loader constraint violation while deploying my Maven based application in JBoss. Good news is, I have solved this issue. Along with the root cause of the issue and it's solutions, today we would also discuss the approach that I have used to solve this issue because using similar approach one could troubleshoot many other similar issues.

Let me share the technology stack and deployment logs first before getting in much details. Also one information, I haven't got any Maven error while building the application.

1. Technology Stack


- JDK 7
- Apache Maven 3.5.2
- JBoss-6.1.0.Final

2. Deployment Logs

16:06:22,202 INFO  [TomcatDeployment] deploy, ctxPath=/QuartzScheduler
16:06:22,249 INFO  [[/QuartzScheduler]] QuartzInitializer: Quartz Initializer Servlet loaded, initializing Scheduler...
16:06:22,249 ERROR [[/QuartzScheduler]] StandardWrapper.Throwable: java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory(
)Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/jboss/classloader/spi/base/BaseClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of org/jboss/cl
assloader/spi/base/BaseClassLoader) for resolved class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type taticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory; used
 in the signature
        at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:299) [:1.6.6]
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:269) [:1.6.6]
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:281) [:1.6.6]
        at org.quartz.impl.StdSchedulerFactory.(StdSchedulerFactory.java:303) [:]
        at org.quartz.ee.servlet.QuartzInitializerServlet.getSchedulerFactory(QuartzInitializerServlet.java:251) [:]
        at org.quartz.ee.servlet.QuartzInitializerServlet.init(QuartzInitializerServlet.java:183) [:]
        at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1208) [:6.1.0.Final]
        at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1108) [:6.1.0.Final]
        at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:3628) [:6.1.0.Final]
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:3851) [:6.1.0.Final]
        at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeployInternal(TomcatDeployment.java:294) [:6.1.0.Final]
        at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeploy(TomcatDeployment.java:146) [:6.1.0.Final]
        at org.jboss.web.deployers.AbstractWarDeployment.start(AbstractWarDeployment.java:476) [:6.1.0.Final]
        at org.jboss.web.deployers.WebModule.startModule(WebModule.java:118) [:6.1.0.Final]
        at org.jboss.web.deployers.WebModule.start(WebModule.java:95) [:6.1.0.Final]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.7.0]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [:1.7.0]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [:1.7.0]
        at java.lang.reflect.Method.invoke(Method.java:601) [:1.7.0]
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157) [:6.0.0.GA]
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96) [:6.0.0.GA]
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:88) [:6.0.0.GA]
        at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:271) [:6.0.0.GA]
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:670) [:6.0.0.GA]
        at org.jboss.system.microcontainer.ServiceProxy.invoke(ServiceProxy.java:206) [:2.2.0.SP2]
        at $Proxy41.start(Unknown Source)  

3. Analyzing the Logs


Logs are true saviour for any developer. If one could analyze the logs properly more then more than half of the job is already done. See the highlighted part of the above logs, we have got some useful information about the error:
- the error was due to method resolution as the class loader of the current class and the class loader for the resolved class have different class objects.
- also the error was related to slf4j jar

But wait, have I used slf4j related jar as my dependency in POM.xml? 
The answer would No. Although I have used log4j as my direct dependency in POM.xml but I haven't used slf4j related any jar as my direct dependency in POM.xml.

Then again two questions arises if we though about the cause of the error,
Q1: My application must be getting slf4j related jar as indirect dependency from somewhere which is conflicting with JBoss libraries at run time. Is it so or not?
Q2: Is it because of two libraries i.e. log4j & slf4j, JBoss is throwing Linkage error at run time? 

Therefore if we have to find the exact jar from the application which has slf4j related jar as its indirect dependency and exclude it from that jar then problem should get solved. Let's try out this.

4. Solution

  • Find out the dependency tree of the application
    One could use mvn dependency:tree command to get the dependency tree of any Maven projects. Let's run it and see the output. See, quartz related jar has slf4j-api jar as it's indirect dependency.
    mvn dependency:tree
    
    Output:
    
    ------------------------------------------------------------------------
    Building QuartzScheduler_Maven 1.0-SNAPSHOT
    ------------------------------------------------------------------------
    [dependency:tree]
    com.anshulsblog:QuartzScheduler_Maven:war:1.0-SNAPSHOT
    +- javax.transaction:javax.transaction-api:jar:1.2:provided
    +- org.quartz-scheduler:quartz:jar:2.2.1:compile
    |  +- c3p0:c3p0:jar:0.9.1.1:compile
    |  \- org.slf4j:slf4j-api:jar:1.6.6:compile
    +- log4j:log4j:jar:1.2.17:compile
    \- junit:junit:jar:4.10:test
       \- org.hamcrest:hamcrest-core:jar:1.1:test
    ------------------------------------------------------------------------
    BUILD SUCCESS
    ------------------------------------------------------------------------
    Total time: 2.181 s
    Finished at: 2018-05-22T16:41:58+05:30
    Final Memory: 9M/22M
    ------------------------------------------------------------------------
  • Dependency Exclusion in Maven
    Let's exclude slf4j-api jar from quartz then again build & deploy the application and see whether it solves the issue.
    <dependency>
     <groupId>org.quartz-scheduler</groupId>
     <artifactId>quartz</artifactId>
     <version>2.2.1</version>
            <exclusions>
      <exclusion>
         <groupId>org.slf4j</groupId>
                       <artifactId>slf4j-api</artifactId>
                    </exclusion> 
            </exclusions>
    </dependency>
    
    Built and deployed the application again, it worked and now the deployment logs are clean. 

5. Conclusion


Even though, if one doesn't get any kind of Maven errors while building the application, it doesn't imply that the application would be successfully deployed always. One could get many deployment errors either due to multiple versions of the same jars(direct & indirect dependencies) or due to multiple jars conflict or due to jar conflict between the container's jar and compile time provided jar. In all such instances, it's better to go through the dependency tree of the project (use  mvn dependency:tree command) and if any conflicts found then exclude it. Happy Learning!!



Tuesday, May 15, 2018

How to check embedded Tomcat server properties in spring boot?

Hello Friends!! Today we would be discussing how to check the embedded Tomcat server properties in Spring Boot. You must be thinking why would we ever want to check the Tomcat properties because we are the one who has set these properties  using Spring Boot's configuration file i. e.  application.yml / application.properties. But let me first tell you the reason behind it, why I have travelled this extra mile and then we would see how to check the properties?

Q1. Why are we even interested in checking the Spring Boot's embedded Tomcat server properties ?


Recently, I have came across the requirement for setting up the maxSwallowSize property in the embedded Tomcat server of my Spring Boot application which I did it successfully by using Java configuration because as of now while writing this post, this property can't be configured using Spring Boot's configuration file i. e.  application.yml / application.properties.

For configuring maxSwallowSize property,  I have used TomcatConnectorCustomizer interface and then associated it with the TomcatEmbeddedServletContainerFactory class that means manually registered TomcatEmbeddedServletContainerFactory bean in the main Spring Boot class. For more details on this, have a look at this write-up.

Now one question crossed our mind,
Does the manually configured Tomcat server honours the bootstrap. yml file containing some of the configured Tomcat server properties if not then do we have to set all the required properties like maxSwallowSize ?
Logically it should but we can't leave it as granted, we must be sure. That's why we find ourselves in first place to look out a way to check embedded Tomcat server properties.

For reference, bootstrap. yml file,
spring:
  application:
    name: anshuls-blog
      
# EMBEDDED SERVER CONFIGURATION  
server:
  port: 8081
  tomcat:
    max-threads: 1000 # Maximum number of worker threads
    min-spare-threads: 40 # Minimum number of worker threads
    uri-encoding: UTF-8 # Character encoding to use to decode the URI

2. How to check  embedded Tomcat server properties in spring boot?


There are two ways for finding out the configured server properties of a embedded Tomcat server. Both involves, getting the required bean from application context and look out for the desired properties in debug mode.

2.1 Get TomcatEmbeddedServletContainerFactory  bean from Application Context 

Look out the properties inside the TomcatConnectorCustomizer.


2.2 Get ServerProperties bean from Application Context 

ServerProperties.java class contains all the supported embedded servers in Spring Boot as the static inner class i.e. Tomcat, Jetty, Undertow [1]. That's why inspecting it in debug mode shows the Tomcat properties.

For reference, code snippet 
public void getEmbeddedTomcatInfoInSpringBoot() {
  
 TomcatEmbeddedServletContainerFactory tomcatServletContainerFactory = context.getBean(TomcatEmbeddedServletContainerFactory.class);
 Collection<TomcatConnectorCustomizer> tomcatConnectorCustomizers = tomcatServletContainerFactory.getTomcatConnectorCustomizers();
  
 logger.info("URU Encoding:>>>>>>>>>" + tomcatServletContainerFactory.getUriEncoding());
 logger.info("Port:>>>>>>>>>" + tomcatServletContainerFactory.getPort());
  
 ServerProperties serverProperties = context.getBean(ServerProperties.class);
  
 logger.info("MaxThreads Property:>>>>>>>>>" + serverProperties.getTomcat().getMaxThreads());
 logger.info("MinSpareThreads Property:>>>" + serverProperties.getTomcat().getMinSpareThreads());
 logger.info("MinSpareThreads Property:>>>>>" + serverProperties.getTomcat().getUriEncoding());
   
}
Thank you for your time and see you in the next post. Happy Learning!!

Appendix:
[1]: ServerProperties.java

Thursday, May 10, 2018

Thymeleaf: jQuery/JavaScript function call with or without parameters (Examples)

While developing our web application, it's very common use case to execute JavaScript functions on an account of any event like onblur, onchange, onclick, onkeydown, onmouseover etc [1]. These calls may be with or without parameters depending upon the business requirement.
             Today, we would see some examples to understand how to properly call JavaScript functions from Thymeleaf. But before that, we would also see used tech stack, Thymeleaf dependencies in the POM file and how we have added page fragments containing our CSS &  JS files in the target HTML page where we would be making the JavaScript function calls.



1. Tech Stack:


- Spring Boot 1.5.10.RELEASE
- Maven 3.3.9
- Thymeleaf 3.0.3.RELEASE

2. Thymeleaf Dependencies in Maven POM file

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
 <groupId>org.thymeleaf</groupId>
 <artifactId>thymeleaf</artifactId>
 <version>3.0.3.RELEASE</version>
</dependency>
<dependency>
 <groupId>org.thymeleaf</groupId>
 <artifactId>thymeleaf-spring4</artifactId>
 <version>3.0.3.RELEASE</version>
</dependency>
<dependency>
 <groupId>nz.net.ultraq.thymeleaf</groupId>
 <artifactId>thymeleaf-layout-dialect</artifactId>
 <version>2.1.2</version>
</dependency>

3. Add external JavaScript file to the HTML page


For cleanliness and better maintainability, I have kept almost all of my JavaScript functions in a separate JS file which is located at <project_name>/src/main/resources/public/js/main.js and then added the fragment containing CSS & JS in HTML file using th:replace attribute.

3.1 The Fragment 

## <project_name>/src/main/resources/templates/fragments/header.html
<head th:fragment="cssandjs">
 <title>Anshul's Blog</title>
 <link rel="stylesheet" type="text/css" th:href="@{/css/screen.css}"/>
 
 <script type="text/javascript" src="https://code.jquery.com/jquery-latest.min.js"></script>
 <script type="text/javascript" th:src="@{/js/main.js}" src="/js/main.js"></script>
</head>

3.2 The Target HTML page 


This is the file where we have added the cssandjs fragment using th:replace attribute and will be making JavaScript calls using Thymeleaf. For more details on th:replace attribute, have a look at this write-up.
## <project_name>/src/main/resources/templates/target.html
<head th:replace="fragments/header :: cssandjs">

4. jQuery / JavaScript Function Calls


Apart from function calls, we would also see situations where we may avoid writing JavaScript functions. One might confuse while making function calls as when to directly use events like onclick, onchange etc or use Thymeleaf's attributes like  th:onclick or th:onchange etc. Therefore, just follow the golden rule i.e. use Thymeleaf's attributes only when, we need to pass some dynamic values in the functions otherwise stick with normal HTML event attributes. Now we ready to fly, everything is in place.

4.1 Function call without parameter

<button onclick="addItemToKart()">Add Item</button>
<div class="close"><span id="x" onclick="closeItemDetailsInModelWindow()">&#9747;</span></div>
<select th:name="${#strings.listSplit(stream.key,',')[1]}" 
  th:onchange="${#strings.listSplit(stream.key,',')[1] == 'Science'} ? 'populateScienceOrCommerceDropdown()' : ''">

4.2  Function call with parameters

## ${item.id} is of type Integer
<input type="button" value="Select" th:onclick="|showItemDetailsInModelWindow(${item.id})|"/>

## ${author.id} is of type Integer & ${author.name} is of type String
<input type="button" value="Show books by author" th:onclick="|showBooksByAuthor(${author.id}, '${author.name}')|"/>

## ${titleModel.isbn} is of type String & ${book.bookId} is of type Integer
<a th:onclick="|bookDetails('${titleModel.isbn}',${book.bookId})|" style="cursor: pointer;">Book Details</a> 

4.3 Avoid writing JavaScript functions


In some situations, one could avoid writing JavaScript functions like when one have to simply call a particular controller's method or when one have to show the popup box [Alert box, Confirm box, and Prompt box] etc.
<button th:onclick="'javascript: document.location=\'/chapterdetails?isbn=' + ${bookModel.isbn} + '&amp;page=1\''"></button>  
<input type="submit" value="Approve" onclick="return ( prompt('You must type APPROVED to continue') == 'APPROVED' )" /> 

5. Conclusion 


Now we know how to make JavaScript function calls in Thymeleaf. We have also seen how to keep function calls in a separate file for better maintainability and then use th:replace attribute to add the fragments containing these CSS & JS files. Happy Learning!!

Appendix:
[1] : Some examples of event attribute and their corresponding event actions:
  • onclick Event:
    onclick of a button, invoke a controller method with or without parameter
    - onclick of a button, open a model window to either show some information to user or to take user's input
  • onchange Event:
    dynamically showing different select box on selecting different values from a select box 

Friday, May 4, 2018

Spring Boot: 'Why' & 'How to' Configure maxSwallowSize property for embedded Tomcat

Hello Friends! Today we would be discussing why in first place, anyone needs to configure maxSwallowSize property and what are the steps that needs to be followed in order to configure this property. Can this property be directly configured by Spring Boot's application.yml / application.properties file or any Java configuration is required for this?



Table Of Content
1. Introduction
2. Why configure maxSwallowSize property
3. How to configure maxSwallowSize property
4. Conclusion

Thursday, May 3, 2018

Difference between Thymeleaf attribute th:replace, th:insert and th:include

Similar to JSP includes, Thymeleaf offers page fragment inclusion but with some important improvements. One could include parts of other pages as fragments (whereas JSP only includes complete pages ) using th:replace or th:insert or th:include. Although the job of all these three attributes are same but how they actually include parts of pages as fragment in the target page is little bit different. It's very important to understand the back-end processing of this attribute otherwise one would get surprising results. That's why, today we would be discussing difference between these attributes.


Functionality


Before describing the attributes functionalities, be familiar with term like:
Host Tag:  tag containing th:replace, th:insert or th:include attribute [would be present in the target page where one would like to add the fragment]
Fragment Tag: tag containing th:fragment attribute [would be present in any page depending upon the design of the page but generally one would store their fragments in modular fashion like header.html or fragments.html]

th:replace - It will actually substitute the host tag by the fragment’s. That means, It will remove the host tag and in place of host tag, it will add the specified fragment including the fragment tag.

th:insert - It will simply insert the specified fragment as the body of its host tag including the fragment tag.

th:include - It will also insert the specified fragment as the body of its host tag but excluding the fragment tag.

Implementation


We have already provided the functionality overview of each of the attributes but it would be more clear after going through this example. We would be adding the the fragment and see the HTML output that's generated by each of the attribute.

Step 1: Add the fragment in the target page
<div id="tagWithReplaceAttribute" th:replace="fragments/header :: targetFragmentToIncludeInOurPage"></div>
<div id="tagWithInsertAttribute" th:insert="fragments/header :: targetFragmentToIncludeInOurPage"></div>
<div id="tagWithIncludeAttribute" th:include="fragments/header :: targetFragmentToIncludeInOurPage"></div>
where,
fragments/header = a template name that one are referencing to. This can be a file or it can reference to the same file either by using the this keyword (e.g. this :: header) or without any keyword (e.g. :: header).
targetFragmentToIncludeInOurPage = expression after double colon is a fragment selector (either fragment name or Markup Selector)

Step 2: Create the fragment to add

Adding it to [/<project_name>/src/main/resources/templates/fragments/header.html]
<div th:fragment="targetFragmentToIncludeInOurPage" id="tagWithFragmentAttribute">
 <div id="contentGoesHere"></div>
</div>
Step 3: The Output
<div id="tagWithFragmentAttribute">
 <div id="contentGoesHere"></div>
</div>

<div id="tagWithInsertAttribute">
 <div id="tagWithFragmentAttribute">
  <div id="contentGoesHere"></div>
 </div>
</div>

<div id="tagWithIncludeAttribute">
 <div id="contentGoesHere"></div>
</div>
Look at the output, now we know which attribute generates which kind of HTML code after processing. Therefore don't confuse with these attributes and use attributes judiciously depending upon the requirements. Happy Learning!!

Monday, April 30, 2018

How to iterate over a List or Map Object in Thymeleaf (With Examples)?

Although Thymeleaf provides an easy way to iterate over List or Map objects but if one doesn't know the exact syntax for iteration then it could be tricky and one might get surprising results. Today we would discuss how to iterate over a List or Map object in Thymeleaf using th:each attribute.


Table Of Content
1. Introduction
2. Iterate Over List Object
3. Iterate Over Map Object
4. Keeping Iteration Status
5. Conclusion

Friday, April 20, 2018

How to construct dynamic URL using Thymeleaf

While creating a web application, it's very common to sends parameters in the request as query string or as the path variables. Recently, I have tried to achieve the same using Thymeleaf but faced some problem because I was new to Thymeleaf. But later found that Thymeleaf provides very simple and straightforward way to create dynamic URLs. Today we would see How? As it could be useful to anyone who would come across the same problem.

We would be using link expressions, a type of Thymeleaf Standard Epression: @{...} to create URLs in our web application.
  1. Passing parameters as Query String
    O/P : <a href="/orderdetails?id=3">
    <a th:href="@{/orderdetails(id=3)}"> 
    <a th:href="@{/orderdetails(id=${order.id})}" th:text="${order.id}">Order ID</a>
    
    Would like to pass several parameters,
    O/P: <a href="/orderdetails?id=3&amp;action=show_all">
    <a th:href="@{/orderdetails(id=3,action='show_all')}">
    
  2. Passing parameters as Path Variables
    O/P : <a href="/orderdetails/3">
    <a th:href="@{/orderdetails/{id}(id=3)}"> 
    <a th:href="@{/orderdetails/{id}(id=${order.id})}" th:text="${order.id}">Order ID</a>
    
    Alternative way:
    <a th:with="id=${order.id}" th:href="@{${'/orderdetails/' + id}}" th:text="${id}">Order ID</a>
    <a th:href="@{${'/orderdetails/' + order.id}}" th:text="${order.id}">Order ID</a>
If you would like to know about how to fetch the data [passed as Query String or as Path Variable using Thymeleaf] from incoming request in your Controller in Sprig MVC then you could checkout my post that describes the Differences between @RequestParam and @PathVariable annotations in Spring MVC? Happy Learning!!

Friday, March 23, 2018

java.sql.SQLException: Can not issue data manipulation statements with executeQuery()

Recently while trying to delete specific rows from a table using JPA query and Native query, I have got java.sql.SQLException. The errors state that :

java.sql.SQLException: Can not issue data manipulation statements with executeQuery().



Although the error messages is pretty much self explanatory. Let me show you the repository class and share the used tech stack then it would give you the right context.

Tech Stack:

- Spring Boot 1.5.7.RELEASE
- Maven 3.3.9
- spring-data-rest-webmvc
- spring-data-rest-core
- spring-boot-starter-data-jpa
- HikariCP

Note: spring-boot-starter-data-jpa contains "tomcat-jdbc" as it's internal dependency. Wondering how am I using HikariCP then . See [1].

Repository Class: 

package com.anshulsblog.service.employee.datalayer.repository;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.transaction.annotation.Transactional;

import com.anshulsblog.service.employee.entity.Employee;

@RepositoryRestResource(path="employee")
@Transactional
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {

 @Transactional( readOnly = true )
        public List findByEmpId(String empID);

 @Query( value = "DELETE from Employee e where e.empId = :id " )
 public void deleteById(@Param("id") String id);
}

Now you see my Repository class and the error, it's evident that internally EntityManager is using executeQuery() method to execute the SQL statements. That's why it's working for SELECT statement but not for DELETE statement. I have also tried to INSERT a dummy data using native query just to check but it has given me the same error.
@Query(nativeQuery = true, value = "INSERT INTO `employee` VALUES(1,"Anshul Agrawal","India")" )
public void tryInsert();

We all know that executeQuery() method is used to execute SQL statements which retrieves some data from database whereas executeUpdate() and execute() method is used to execute SQL statements which update or modify the database. But here we are not manually executing these methods therefore I thought there must be some out of box solution provided by spring-data module as a convention.

Solution


Just add the @Modifying annotation to the repository method then one could also execute DML statements like DELETE, INSERT or UPDATE. This annotation would trigger the query annotated to the method as updating query instead of a selecting one. We have other solution also like one could provide custom implementation for their Spring Data repositories. So now our methods becomes:
import org.springframework.data.jpa.repository.Modifying;
 
@Modifying
@Query( value = "DELETE from Employee e where e.empId = :id " )
public void deleteById(@Param("id") String id);

Appendix 

[1] - Excluded tomcat-jdbc from spring-boot-starter-data-jpa, now by default Spring Boot will use HikariCP .

Happy Learning!! :-)

Saturday, March 10, 2018

Create your first Spring Boot web application with Maven & Thymeleaf: 4 Steps(with Screenshots)

Hello Friends!! If you have ever developed the enterprise spring-based applications then you would surely know the pain for making bulky configuration along with the complicated dependency management. Today we would see how Spring Boot takes this pain away. To demonstrate this, we would discuss step by step process to create our first Spring Boot web application using Spring Tool Suite(STS) and then explain how this has become possible using Spring Boot. Don't worry if haven't developed any spring-based application before because this would be very easy to follow guide.
Table Of Content
1. Introduction
2. Scope
3. Tools & Technology Stack Used
4. Steps to create web application
5. Why Spring Boot?
6. Conclusion

Saturday, February 17, 2018

How to configure Maven projects to use a specific JDK version?

Hello friends, today the scope of our discussion would be related to configuring Maven project and  cross-compilation feature of Java. Precisely we would talk about below points:
  • the right way of configuring Maven projects to use specific JDK version
  • important pointers related to Java compiler & it's cross compilation feature 
  • common misconception while configuring the Maven compiler plugin 

Friday, February 2, 2018

java.lang.NoClassDefFoundError: javax/transaction/TransactionManager

Recently while trying to migrate one of the application from JDK6 to JDK7 & Spring 3.x to Spring 4.x, I have got Spring  BeanCreationException along with nested exception related to javax TransactionManger while deploying the application in Tomcat 7.

Before sharing the logs, providing the tech stack:
- Maven based application
- Spring 4.x [4.3.0.RELEASE from 3.1.0.RELEASE]
- Tomcat 7.0.83
- JDK 7 [1.7.0_05]

Error Logs:

org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'xyz' defined in class path resource [xyz/xyz.xml]: 
Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: 
javax/transaction/TransactionManager 

Solution:

Don't be confused with the BeanCreationException, the issue is happening due to missing jta jar.
Add the below Maven dependency and issue will be resolved:
<dependency>
    <groupId>javax.transaction</groupId>
    <artifactId>jta</artifactId>
    <version>1.1</version>
</dependency>