Wednesday, November 5, 2014

Java data type conversion

Java auto boxing is a nice feature but it can sometimes cause a lot of problems, especially when going from Object to primitive. A NullPointerException can be very hard to spot, because it can be throw in strange places where you normally would not expect it. See this for some auto boxing errors.
This blog will list some nice data type conversion between different data type and from primitive and Object type and vise versa.

Integer/int conversion
See examples here. 

Data type from, to Use Comment
int to Integer int i = 10; 
Integer intObj = Integer.valueOf(i);

int to Long int i = 10;
Long longObj= Long.valueOf(i);

int to long int i = 10;
long l = (long) i;

int to String int i = 10;
String s = Integer.toString(i);

Integer to int Integer intObj = new Integer(10);
int i = intObj.intValue();
NumberFormatException will be thrown if the intObj is a null Integer.
Integer to String Integer intObj = new Integer(10);
String s = intObj.toString();
NumberFormatException will be thrown if the intObj is a null Integer.
Integer to long Integer intObj = new Integer(10);
long l = intObj.longValue();
NumberFormatException will be thrown if the intObj is a null Integer.
Integer to Long Integer intObj = new Integer(10);
Long longObj = Long.valueOf(intObj.longValue());
NumberFormatException will be thrown if the intObj is a null Integer.

Long/long conversion
Careful when converting from Long/long to Integer/int. No exception is thrown if the Long value is bigger than Integer.MAX_VALUE or smaller than Integer.MIN_VALUE. It will simple do an int overflow and the output will be unexpected.
See examples here
long to Long long l = 10L;
Long longObj = Long.valueOf(l);

long to Integer long l = 10L;
Integer intObj = Integer.valueOf(Long.valueOf(l).intValue());
No really good way of doing this. Overflow may occur.
long to String long l = 10L;
String s = Long.toString(l);

long to int long l = 10L;
int i = (int) l;
Use simple cast.
Overflow may occur.
Long to long Long longObj = new Long(10L);
long l = longObj.longValue();
NumberFormatException will be thrown if the longObj is a null Long.
Long to String Long longObj = new Long(10L);
String s = longObj.toString();

Long to Integer Long longObj = new Long(10L);
Integer intObj = Integer.valueOf(longObj.intValue());
No really good way of doing this. Overflow may occur.
Long to int Long longObj = new Long(10L);
int i = longObj.intValue();
Overflow may occur.

Saturday, October 18, 2014

Spring JPA/Hibernate configuration without XML

With the lovely spring feature @Configuration you can now completely drop all XML configuration. In this blog I will go through how to configure JPA/Hibernate and get rid of XML bean configuration and the persistence.xml often used with JPA. Start by instrumenting the configuration class with:

  @Configuration   
  @EnableJpaRepositories(basePackages = "com.blogspot.jpdevelopment.immutable.hibernate")   
  @EnableTransactionManagement   
  public class JpaConfig {   


@Configuration Indicates that a class declares one or more @Bean methods and may be processed by the Spring container.

@EnableJpaRepositories Will scan the package of the annotated configuration class for Spring Data repositories. This means classes annotated with @Repository.

@EnableTransactionManagement Enables Spring's annotation-driven transaction management capability, similar to the support found in Spring's <tx:*> XML namespace. Typically the XML configuration looks like this:

 <tx:annotation-driven transaction-manager="transactionManager"/>  

Now it's time to declare beans. A javax.sql.DataSource bean is needed.
 @Bean  
 public DataSource dataSource() {  
      BasicDataSource dataSource = new BasicDataSource();  
      dataSource.setDriverClassName("com.mysql.jdbc.Driver");  
      dataSource.setUrl("jdbc:mysql://localhost:3306/test");  
      dataSource.setUsername("root");  
      return dataSource;  
 }  

Next we need a JpaVendorAdapter. This serves as single configuration point for all vendor-specific properties.

 @Bean  
 public JpaVendorAdapter jpaVendorAdapter() {  
      HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();  
      hibernateJpaVendorAdapter.setShowSql(false);  
      hibernateJpaVendorAdapter.setGenerateDdl(true);  
      hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);  
   
      return hibernateJpaVendorAdapter;  
 }  

With the datasource and jpaVendorAdaptor in place we can make a LocalContainerEntityManagerFactoryBean. This will expose a EntityManagerFactory and inject it in the classes defined in the packagesToScan.
 @Bean  
 public LocalContainerEntityManagerFactoryBean entityManagerFactory() {  
      LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();  
      entityManagerFactoryBean.setDataSource(dataSource());  
      entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());  
      entityManagerFactoryBean.setPackagesToScan("com.blogspot.jpdevelopment.immutable.hibernate");  
      return entityManagerFactoryBean;  
 }   

Finally we need a PlatformTransactionManager.

 @Bean  
 public PlatformTransactionManager transactionManager() {  
      return new JpaTransactionManager(entityManagerFactory().getObject());  
 }  


Now lets the it for a spin and make a repository. A simple way to get started is to use the CrudRepository interface.

 @Repository  
 public interface PersonRepository extends CrudRepository<Person, UUID> {  
 }  

And the implementation.

 public class PersonAccessRepository implements PersonRepository {  
   
      @PersistenceContext  
      private EntityManager entityManager;  
   
      @Override  
      public Person findOne(UUID id) {  
           return this.entityManager.find(Person.class, id);  
      }  
   
      @Transactional  
      @Override  
      public <S extends Person> S save(S person) {  
           this.entityManager.persist(person);  
           return person;  
      }  
 }  


Full example with dependencies and executable code can be found here.

Working with immutable objects and hibernate

To support a rich domain model, it's often a good idea to make domain objects immutable. Hibernate if however not happy about this. It works best with objects who only has a default constructor and getter and setters for all fields. 
To make hibernate work with immutable objects, declare a default constructor with at least package level visibility. 
If mapping-annotations is placed on fields the access type will be AccessType.FIELD. If placed on methods the access type will be AccessType.PROPERTY. Field type access is needed by hibernate for handling final attributes.
 
 @Entity  
 @Table(name = "person")  
 public class Person {  
   
      @Id  
      @Column(columnDefinition = "BINARY(16)", length = 16)  
      private final UUID id;  
      private final Date creationDate;  
      private final String firstname;  
      private final String lastname;  
   
      // Hibernate needs this or it will fail with an InstantiationException  
      private Person() {  
           this.id = UUID.randomUUID();  
           this.creationDate = new Date();  
           this.firstname = null;  
           this.lastname = null;  
      }  
   
      public Person(String firstname, String lastname) {  
           this.id = UUID.randomUUID();  
           this.creationDate = new Date();  
           this.firstname = firstname;  
           this.lastname = lastname;  
      }  
 }  

If you are using XML mappings, this can also be done by setting:

<hibernate-mapping default-access="field" package="com.blogspot.jpdevelopment.immutable.hibernate.core.domain">

A full example is available here.

Sunday, March 9, 2014

RESTEasy format timestamps as date

By default RESTEasy using Jackson will format a java.util.Date as a unix-timestamp. To change it into ISO_8601 formar, yyyy-MM-dd'T'hh:mm:ss'Z', simply create a class
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;

/**
 * This class will make sure JSON timestamps is written in the format yyyy-MM-dd'T'hh:mm:ss'Z' 
 */

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonConfig implements ContextResolver<ObjectMapper> {

 private final ObjectMapper objectMapper;

 public JacksonConfig() {
  objectMapper = new ObjectMapper();
  objectMapper.configure(
    SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
 }

 @Override
 public ObjectMapper getContext(Class<?> objectType) {
  return objectMapper;
 }
}

Configur Eclipse to use WildFly 8

In order to configure Wildfly/JBoss from Eclipse, start by installing the plugin "JBoss Tools" from Eclipse Marketplace. You only need to install JBossAS Tools, but you may install everything if you like:
After installing and restarting eclipse, go to File | New | Server and expand the JBoss Community option. Choose "WildFly 8 (Experimental)" and click Next
Now choose the location for the WildFly 8 installation and a JRE.

Remember that WildFly requires a JDK 1.7, therefore you will not be able to start it with an older JDK version.


The wizard will now ask if you wish to deploy a project. Choose the project you wish to deploy and click Add >.

Click Finish. WildFly 8 is now configured on your Eclipse environment! 
To enable automatic publishing of code changes, double click the server in the server tab:

This will open a server configuration window. In the "Publishing" section, set to check "Automatically publish after a build event" and set the interval to whatever fits you. In my experiences, 5 seconds works best. 
Finally change the value in the "Application Reload Behavior" section to: "\.jar$|\.class$"



Happy developing!

Monday, January 27, 2014

RESTEasy services with older application servers

If you are not blessed with the latest application server and want to use all the fancy new features offered by RESTEasy, fear not! You can still use RESTEasy framework with older application servers like JBoss 4.x.


Add the 4 dependencies below. If you are using maven, here is a shortcut: 
<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>resteasy-jaxrs</artifactId>
 <version>3.0.6.Final</version>
</dependency>

<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>jaxrs-api</artifactId>
 <version>3.0.6.Final</version>
</dependency>

<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>resteasy-jaxb-provider</artifactId>
 <version>3.0.6.Final</version>
</dependency>

<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>resteasy-jackson2-provider</artifactId>
 <version>3.0.6.Final</version>
</dependency>  

Loading the RESTEasy framework is very easy. Simple configure it in web.xml.
<servlet>
 <servlet-name>Resteasy</servlet-name>
 <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>

<!-- Set servlet-mapping for the Resteasy servlet if it has a url-pattern other than /* -->
<servlet-mapping>
 <servlet-name>Resteasy</servlet-name>
 <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

<context-param>
 <param-name>resteasy.scan</param-name>
 <param-value>true</param-value>
</context-param>

<context-param>
 <param-name>resteasy.servlet.mapping.prefix</param-name>
 <param-value>/rest</param-value>
</context-param>

<listener>
 <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>

To make spring available in the rest services, add another listener in the web.xml.
<listener>
 <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>

And now a simple JSON REST service, to check everything works.

A simple POJO class:
public class RestObject {

 private long id;
 private String name;
 private String value;

 public long getId() {
  return this.id;
 }

 public void setId(long id) {
  this.id = id;
 }

 public String getName() {
  return this.name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getValue() {
  return this.value;
 }

 public void setValue(String value) {
  this.value = value;
 }
}

And a service who offers two methods. One who consumes and produces a JSON POST request and another who produces JSON.
@Path("/v1")
public class RestService {

 @POST
 @Path("/post-service")
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
 public Response addRestObject(RestObject restObject) {
  restObject.setId(123L);
  return Response.status(HttpResponseCodes.SC_OK).entity(restObject).build();
 }

 @GET
 @Path("/get-service/{id}")
 @Produces(MediaType.APPLICATION_JSON)
 public Response getRestObject(@PathParam("id") long id) {
  RestObject restObject = new RestObject();
  restObject.setId(id);
  restObject.setName("your name");
  restObject.setValue("JP");
  return Response.status(HttpResponseCodes.SC_OK).entity(restObject).build();
 }
}

Accessing the GET method, http://localhost:8080/war-file/rest/v1/get-service/2 will output:
{
    "id": 2,
    "name": "your name",
    "value": "JP"
}

Accessing the POST, http://localhost:8080/war-file/rest/v1/post-service method with payload:

{
    "id": 1,
    "name": "my name",
    "value": "JP"
}

Will output:

{
    "id": 123,
    "name": "my name",
    "value": "JP"
}

That is all it takes to get started with RESTEasy using an older application server, happy REST/SOAP service development :).

Tuesday, January 21, 2014

JBoss 4.2.2 to Wildfly8/Jboss7 CXF migration

Prelude

Recently I was facing a migration project, migrating from from JBoss 4.2.2 to Wildfly 8. The old project was using Spring 2.5.5, Hibernate 3.6.7 and CXF 2.2.7.
Everything except CXF was fairly easy to migrate. Wildfly 8 comes with CXF 2.7.7 bundled and I wanted to use the managed dependencies. 
I have made this post to hopefully help other people facing a migration from an older JBoss to a more resent version.

Before starting any migration I would strongly recommend making sure you have at least some smoke tests of all services.
For old legacy systems no test might exist, but making a few smoke tests that exercise as much as possible of the service could work.   
An excellent tool for testing SOAP web service is SoapUI.

I have added short description of the project configuration in the bottom of the post.

Happy reading! 


Here we go!

First I made sure all CXF dependencies was removed from the war file, but WSDL and XSD files were causing a problem.


First try deploying, resulted in some problems loading the CXF beans from cxf-beans.xml.


ERROR [org.springframework.web.context.ContextLoader] (MSC service thread 1-5) Context initialization failed: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath:/cxf-beans.xml]
Offending resource: ServletContext resource [/WEB-INF/classes/applicationContext.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://cxf.apache.org/jaxws]
Offending resource: class path resource [cxf-beans.xml]
        at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68) [spring-2.5.5.jar:2.5.5]
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85) [spring-2.5.5.jar:2.5.5]
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76) [spring-2.5.5.jar:2.5.5]
I solved this by completely removing cxf-beans.xml and let Wildfly manage the services.
Unfortunately this didn't solve all my problems. Now I was facing problems with the XSD's.
We used to create web services by, first creating a WSDL and XSD files and then running wsdl2jave, generating model and interface. 

Caused by: org.apache.ws.commons.schema.XmlSchemaException: Unable to locate imported document at '/ServiceObject.xsd', relative to 'vfs:/C:/Development/wildfly-8.0.0.CR1/bin/content/project.war/WEB-INF/classes/ServiceV1.wsdl#types1'.

After hours of googling about the problem, I decided to get rid of all WSDL and XSD's and let Wildfly handle everything. I removed the wsdlLocation = "classpath:ServiceV1.wsdl", from @WebService annotation and deleted alle WSDL and XSD's from the project. 

First success! The project was now able to deploy. However Wildfly was not showing any registered services in the console :(. 
The problem here was, that I was using standalone-full.xml, which did not have web services enabled by default.
Easy solved by adding:

<extension module="org.jboss.as.webservices">   
and
<subsystem xmlns="urn:jboss:domain:webservices:1.2">
 <modify-wsdl-address>true</modify-wsdl-address>
 <wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
 <endpoint-config name="Standard-Endpoint-Config"/>
 <endpoint-config name="Recording-Endpoint-Config">
  <pre-handler-chain name="recording-handlers" protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
   <handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
  </pre-handler-chain>
 </endpoint-config>
 <client-config name="Standard-Client-Config"/>
</subsystem>   

to standalone-full.xml.

The Wildfly console was now showing all my services. Wohoo!
However my newly gained success only lasted until i clicked the WSDL link :(.
I was now presented to a nice stack trace...
Exception handling request to /project/ServiceV1: java.lang.AbstractMethodError: org.apache.xerces.dom.DeferredDocumentImpl.setXmlStandalone(Z)V
If you have any dependencies to xerces either remove it if possible or use the version provided by Wildfly.

A quick check list to run through: 
  • Remove all WSDL and XSD files
  • Remove wsdlLocation in @WebService element
  • If Services was previously mapped using a name in the WSDL, change "serviceName" to reflect the right name of the service
  • Service endpoints can be found in the web console: http://localhost:9990/console/App.html#webservice-runtime
  • Make sure model classes is properly decorated with XML annotations according to XSD's. If originally generated from XSD's, it should not be a problem
  • Make sure xerces dependency is managed by Wildfly

Sample project configuration

The project structure was looking something like this:

war \
---- WEB-INF \
-------- web.xml
-------- lib \
------------ cxf-2.2.7.jar
-------- classes \
------------ applicationContext.xml
------------ cxf-beans.xml
------------ ServiceV1.wsdl
------------ ServiceObjectV1.xsd
------------ com.blogspot.jpdevelopment.v1.ServiceV1.class
------------ com.blogspot.jpdevelopment.v1.ServiceV1Impl.class
------------ com.blogspot.jpdevelopment.v1.ServiceObjectV1.class   

Web service implementation was looking like this:
@WebService(name = "ServiceV1",
   serviceName = "ServiceV1",
   portName = ServiceV1LOCAL",
   targetNamespace = "http://schema.jpdevelopment.blogspot.com/v1",
   wsdlLocation = "classpath:ServiceV1.wsdl",
   endpointInterface = "com.blogspot.jpdevelopment.v1.ServiceV1")

public class ServiceV1Impl implements ServiceV1 {            

And the interface:
@WebService(targetNamespace = "http://schema.jpdevelopment.blogspot.com/v1", name = "ServiceV1")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface ServiceV1 {

CXF was started in web.xml
<web-app>
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>WEB-INF/classes/applicationContext.xml</param-value>
 </context-param>
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <listener>
  <listener-class>com.blogspot.jpdevelopment.ContextLoadListener</listener-class>
 </listener>
 <servlet>
  <servlet-name>CXFServlet</servlet-name>
  <display-name>CXF Servlet</display-name>
  <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>CXFServlet</servlet-name>
  <url-pattern>/ws/*</url-pattern>
 </servlet-mapping>
</web-app> 

Web service end points was configured in cxf-beans.xml
<bean name="serviceV1Impl" class="com.blogspot.jpdevelopment.v1.ServiceV1Impl">
 <property name="someService" ref="someService" />
</bean>

<jaxws:endpoint id="serviceV1"
 implementor="#serviceV1Impl" address="/serviceV1"
 wsdlLocation="classpath:ServiceV1.wsdl">
</jaxws:endpoint>  

XSD's was referenced inside the WSDL with relative paths, because the project should be deployable to both test and production with any modifications to the generated was file.