Category Archives: Java

Solving character encoding issue with Spring REST


While working on one of spring integration project, we fetched an XML using REST service and while we dumped it, we observed that many of characters were jumbled -which means encoding setting was screwed up. Spring integration configuration code

<int-http:outbound-gateway request-channel="testChannel"
		url="${test.url}" http-method="GET" expected-response-type="java.lang.String"
		reply-channel="glHeaderEnricher" charset="iso-8859-1">
		<int-http:uri-variable name="site_code"
			expression="payload" />
	</int-http:outbound-gateway>

As above mentioned, we were setting the expected char set as well.
“http:outbound-gateway” from Spring is nothing but a wrapper around Spring REST template, so started investigating what going on with REST template. REST template has option to inject message converters, by default converters which get registered are ByteArrayHttpMessageConverter, StringHttpMessageConverter, and ResourceHttpMessageConverter.

In spring integration configuration we had set “expected-response-type=”java.lang.String”” was causing StringHttpMessageConverter to be selected and used, and hence even before the XML payload reached our system it had lost it’s encoding.

Solution? using ByteArrayHttpMessageConverter, which can be done by setting

<int-http:outbound-gateway request-channel="testChannel"
		url="${test.url}" http-method="GET" expected-response-type="byte[]"
		reply-channel="glHeaderEnricher" charset="iso-8859-1">
		<int-http:uri-variable name="site_code"
			expression="payload" />
</int-http:outbound-gateway>

Once read as a raw byte it can be converted to string in any encoding.

How to log query parameters passed to JPA queries


I am using JPA with hibernate underneath. Using the property

<property name="hibernate.show_sql" value="true"/>

Shows just the SQL and not the values of parameters passed -it displays ? marks for query parameter as incomeexpe0_.transactiondate)>=?
Want to know what was the exact parameters passed -This is real helpful for debugging.
This can be achieved using hibernate logging -Add following two lines in your log4J.properties file

log4j.logger.org.hibernate.SQL=TRACE
log4j.logger.org.hibernate.type=TRACE

If this is used “log4j.logger.org.hibernate.SQL=TRACE” -No need to use property hibernate.show_sql, it wil take care of dumping queries.
The secondstatement, “log4j.logger.org.hibernate.type”, logs the JDBC parameters passed to a query

TRACE [main] (BasicBinder.java:83) - binding parameter [1] as [TIMESTAMP] - Thu Jan 03 01:00:18 IST 2013
TRACE [main] (BasicBinder.java:83) - binding parameter [2] as [TIMESTAMP] - Thu Jan 03 23:00:19 IST 2013

For even more advanced analysis and precise JDBC formatted queries (Non in an ORM form, but REAL sql), jdbc proxy driver like P6Spy can be used.

Advantages of a separate DAO layer


With the arrival of ORM most of operations related to DB, like managing connections, transaction management have been abstracted to a certain extent and this has led to many people believe that we can directly call the entitymanager from service layer. I agree that we hardly change persistence layer ( atleast in services, for products its very much can be a valid scenario), But then can we overlook following advantages of DAO layer (All related to DRY)?

  1. Exception handling at a centralized location for all DAO issues -most of time service layer just pass on the failure to client and do not take any action. DAO can logg the exception, for example hibernate exception, log the query -these all can help dig the issue, and throw a runtime exception which will keep service layer code cleaner
  2. What if same query is being called from multiple location -even inside same service, for example “get list of all students”. A change in in this query, lets say an additional criteria, will have to be tracked across all occurence . If there is DAO, it will be delegated there and changes wil be at single place
  3. A well designed DAO layer can be used across projects -for example recently I wrote a DAO for JCR queries, and most of its part as create node, create heirarchical node, delete node etc were exposed in a manner that the lib was used across project
  4. We might not change the DB, but may be ORM itself need to be changed -for example one of client code which needed a deployment on Google apps had to change from hibernate to JPA (Google apps support JPA but not hibernate) -having a separate DAO made life simpler
  5. On flip side, this does introduce more layers and extra level of delegation, but I feel it’s worth it.

Numeric null check on java server side failing with Flex BlazeDS AMF channel


One of the entities developed had a Numeric field as primary key, with a custom code to populate it rather than utilizing any auto generation strategy of JPA

if(ledegrHead.getLedgerHeadId()==null){
ledegrHead.setLedgerHeadId(financePersistence.getNextLedgerHeadId());
}

I wrote junit to test this and obviously it passed -if ID was set to null it would generate an ID.
But the moment I integrated it with flex, things went bad and it would NOT generate the expected “First” ID.
Reason – I had used autobinding on flex side –

[RemoteClass(alias="com.school.questionbank.Question")]
[Bindable]

This resulted in “auto” initialization of integer filed to zero and hence the condition of ==null would always fail. Solution? -explicit check for null as well as zero:

if(ledegrHead.getLedgerHeadId()==null||ledegrHead.getLedgerHeadId()<=0){
ledegrHead.setLedgerHeadId(financePersistence.getNextLedgerHeadId());
}

Comparing Integer in Java -autoboxing does not apply there


Hmm.. it came as most basic surprise for me, I wrote

this.questionId==question.getQuestionId()

where questionid is of type Integer (Object and not primitive).

Logically, it’s a reference comparison and should fail, but since its a wrapper for primitive type and a “special” scenario, my expectation was autoboxing will also apply here and will work properly, but no – it did not.
Correct way is either to use equals or just use intvalue

this.questionId.intValue()==question.getQuestionId().intValue()

Data truncation exception while joining one to one in JPA


Lets say a class is having one to one relation ship with other entity, it looks like

public class StudentDetails implements Serializable{
    @OneToOne(cascade={CascadeType.REFRESH,CascadeType.MERGE},fetch = FetchType.EAGER) 
    @Column(name="classid")
    private ClassDetails classId;
}

When I tried to save rows in the table, it threw an exception

javax.persistence.PersistenceException: org.hibernate.exception.DataException: Data truncation: Data too long for column 'classid' at row 1
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306)
}

What went wrong? When I looked at generated table the filed type for classid was LOB while I expected it to be an int (It just an ID from foreign key). The culprit is -using column instead of joincolumn

public class StudentDetails implements Serializable{
    @OneToOne(cascade={CascadeType.REFRESH,CascadeType.MERGE},fetch = FetchType.EAGER) 
    @Column(name="classid")  
    private ClassDetails classId;

Instead of column, it should be join column

    @OneToOne(cascade={CascadeType.REFRESH,CascadeType.MERGE},fetch = FetchType.EAGER) 
    @JoinColumn(name="classid",nullable=false) <strong> See the joincolumn </strong> 
	private ClassDetails classId;}

If join column is not specified, JPA assumes that ClassDetails object will be saved (along with its all nested graph) to DB and hence it creates a LOB type -telling it that its a joined foreign key resulted in a int data type for the field.

Persisting a detached entity in JPA


In a JPA many to many relationship, if cascade type has been set at CascadeType.PERSIST (or CascadeType.ALL, which includes CascadeType.PERSIST), then while saving the parent and updating it with references of the child, it will try to save the child again.

	@ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH},fetch = FetchType.EAGER)
	@JoinTable(name="QP_Q", 
	joinColumns={@JoinColumn(name="questionpaperid")}, inverseJoinColumns=@JoinColumn(name="questionid"))

Following issues can appear

  1. Child is already in persistence store (A detached instance has been passed) -in this case it will throw an exception “org.hibernate.PersistentObjectException: detached entity passed to persist”
  2. Child is a new entry, then it will be added in its table and operation will complete successfully

Following are some solutions

  1. If requirement is that Parent should add a existing but detached child(creating an instance with same ID and passing on from the client) -it needs to be reattached to session first. Hmm -for this there is NO way in JPA -Nope, merge does not reattach and entity. If you are using hibernate, you are lucky, merge can do the trick
    For JPA, best option would be to query for entity on server side before trying to save it.
  2. If its sure that only new child will be added, and not an detached instance from DB, CascadeType.PERSIST will take care of
  3. On the other hand, if requirement is never to add a new child if its not alredy in DB then CascadeType.PERSIST should be removed and cascade={CascadeType.MERGE,CascadeType.REFRESH} should be used
	@ManyToMany(cascade={CascadeType.MERGE,CascadeType.REFRESH},fetch = FetchType.EAGER)
	@JoinTable(name="QP_Q", 
	joinColumns={@JoinColumn(name="questionpaperid")}, inverseJoinColumns=@JoinColumn(name="questionid"))

Fetching Nested collections in JPA


While coding in JPA with hibernate underneath I got an exception org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags. I was using “LIST” for the association and fetching eagerly

	@ManyToMany(cascade={CascadeType.MERGE,CascadeType.REFRESH},fetch = FetchType.EAGER)
	@JoinTable(name="class_subject", 
	joinColumns={@JoinColumn(name="classid")}, inverseJoinColumns=@JoinColumn(name="subjectid"))
	private List<SubjectDetails> subjects;

The problem seems to be two fold:

  1. JPA allows only two level of nesting for collection, Parententity->Childentity is fine but it does not allow Parententity->childentity->SubChildEntity
  2. Using List for collection instead of SET -remember a SET guarantees unique elements while list does not

What could be solution:

  1. Use SET instead of List and thats what I have done for the moment
	private SET<SubjectDetails> subjects;

  • Hibernate does allow, so we can use specific annotation but it will defy the whole purpose of using JPA
  • Review the model, instead of depending on Object graph to be fetched “Automagically” by ORM, can we move the logic in service layer and do the population as on need basis for required UI? And if you say it would throw lazy initialization because you have used session at DAO -Red Flag -its an anti pattern
  • Never use data which can be localized as part of business logic


    I was reviewing a code and came across something as

     
    public doSomeStuff(String shortMonthName){
     if(shortMonthName.equlaIgnoreCase("jan")){
     //do something}
    }
    

    .
    In this code client passes a month name based on which some logic is executed.

    At first it might look as whats wrong? hmm ..what if in future multilingual support is introduced -the month names will be localized and the client supplies equivalant of “jan” in a language other than english –it will simply fail.This is a very simplistic use case, but hope I make my point

    Never use data which can be localized as part of a business logic 

    Path parameter to FileInputStream


    A basic discovery about FileInputStream 🙂
    FileInput stream always takes a absolute path

    new FileInputStream("must be an absolute path")

    .. if a relative path is given and even if that relative path is added in the class path then also it will not work.