Spring batch read from xml file and write to Database. need step1 auto generated key for step2 - mysql

As seen in below code in step1 I'm reading users.xml and writing to database now in step2 I'm reading from userdetails.xml and writing to database but I need step1 auto generated key of tbl_user for step2. How Can I do that?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<import resource="../config/context.xml" />
<import resource="../config/database.xml" />
<bean id="xmlItemReader1" class="org.springframework.batch.item.xml.StaxEventItemReader">
<property name="resource" value="file:xml/outputs/users.xml" />
<property name="fragmentRootElementName" value="user" />
<property name="unmarshaller" ref="userUnmarshaller"/>
</bean>
<bean id="xmlItemReader2" class="org.springframework.batch.item.xml.StaxEventItemReader">
<property name="resource" value="file:xml/outputs/userdetails.xml" />
<property name="fragmentRootElementName" value="userdetail" />
<property name="unmarshaller" ref="userUnmarshaller"/>
</bean>
<bean id="itemProcessor1" class="com.qmetry.recovery.mapper.UserItemProcessor" />
<bean id="itemProcessor2" class="com.qmetry.recovery.mapper.UserDetailItemProcessor" />
<job id="testJob2" xmlns="http://www.springframework.org/schema/batch">
<step id="step2_1">
<tasklet transaction-manager="transactionManager">
<chunk reader="xmlItemReader1" writer="databaseItemWriter1" processor="itemProcessor1"
commit-interval="100" />
</tasklet>
<listeners>
<listener ref="testListener" />
</listeners>
</step>
<step id="step2_2">
<tasklet transaction-manager="transactionManager">
<chunk reader="xmlItemReader2" writer="databaseItemWriter2" processor="itemProcessor1"
commit-interval="100" />
</tasklet>
</step>
</job>
<bean id="testListener" class="com.qmetry.recovery.mapper.TestListener" scope="step" />
<bean id="databaseItemWriter1" class="org.springframework.batch.item.database.JdbcBatchItemWriter">
<property name="dataSource" ref="dataSource" />
<property name="sql">
<value>
<![CDATA[
insert into TBL_USER(USERNAME,EMAILID)
values (?, ?)
]]>
</value>
</property>
<!--We need a custom setter to handle the conversion between Jodatime LocalDate and MySQL DATE BeanPropertyItemSqlParameterSourceProvider-->
<property name="itemPreparedStatementSetter">
<bean class="com.qmetry.recovery.mapper.UserItemPreparedStatementSetter"/>
</property>
</bean>
<bean id="databaseItemWriter2" class="org.springframework.batch.item.database.JdbcBatchItemWriter">
<property name="dataSource" ref="dataSource" />
<property name="sql">
<value>
<![CDATA[
insert into TBL_USERDETAIL(USERID,CONTACT)
values (?, ?)
]]>
</value>
</property>
<!--We need a custom setter to handle the conversion between Jodatime LocalDate and MySQL DATE BeanPropertyItemSqlParameterSourceProvider-->
<property name="itemPreparedStatementSetter">
<bean class="com.qmetry.recovery.mapper.UserDetailItemPreparedStatementSetter"/>
</property>
</bean>
users.xml
<?xml version="1.0" encoding="UTF-8"?><users>
<user>
<userId>1</userId>
<userName>Taher</userName>
<emailId>taher.tinwala#hotmail.com</emailId>
</user>
</users>
userdetails.xml
<?xml version="1.0" encoding="UTF-8"?><userdetails>
<userdetail>
<userDetailId>1</userDetailId>
<userId__TblUser>1</userId__TblUser>
<contact>1111111111</contact>
</userdetail>
<userdetail>
<userDetailId>2</userDetailId>
<userId__TblUser>1</userId__TblUser>
<contact>2222222222</contact>
</userdetail>
<userdetail>
<userDetailId>4</userDetailId>
<userId__TblUser>1</userId__TblUser>
<contact>4444444444</contact>
</userdetail>
</userdetails>

You need to pass data to a future step. For explantory documentation see http://docs.spring.io/spring-batch/trunk/reference/html/patterns.html#passingDataToFutureSteps
I have implemented the example from the documentation and adjusted it to your configuration with some assumptions here and there.
During the read (or the write, it depends when you get the data that you want to pass) in step 1 you need to store the data in the StepExecution. Add to your xmlItemReader the following:
public class YourItemReader implements ItemReader<Object>
private StepExecution stepExecution;
public void read(Object item) throws Exception {
// ...
ExecutionContext stepContext = this.stepExecution.getExecutionContext();
stepContext.put("tbl_user", someObject);
}
#BeforeStep
public void saveStepExecution(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
Your xml will look like this:
<step id="step2_1">
<tasklet transaction-manager="transactionManager">
<chunk reader="xmlItemReader1" writer="databaseItemWriter1" processor="itemProcessor1" commit-interval="100" />
</tasklet>
<listeners>
<listener ref="testListener" />
<listener ref="promotionListener"/>
</listeners>
</step>
Add the promotionListener bean:
<beans:bean id="promotionListener" class="org.springframework.batch.core.listener.ExecutionContextPromotionListener">
<beans:property name="keys" value="tbl_key"/>
</beans:bean>
And finally you need to retrieve the value in step 2. Again asuming you need it in the reader of step 2 you reader in step 2 needs the following code added:
public class YourItemReader2 implements ItemReader<Object>
private Object someObject;
#BeforeStep
public void retrieveInterstepData(StepExecution stepExecution) {
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext jobContext = jobExecution.getExecutionContext();
this.someObject = jobContext.get("tbl_key");
}
Now you have acces to the value read in step 1.
EDIT - adding some example configuration for an extra read step:
After step 1 add a simple step 2 with the following reader to get the new value from the database
<bean id="itemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader"
scope="step">
<property name="dataSource" ref="dataSource" />
<property name="sql">
<value>
<![CDATA[
YOUR SELECT STATEMENT
]]>
</value>
</property>
<property name="rowMapper" ref="rowMapper" />
</bean>
And a simple rowMapper bean
<bean id="rowMapper" class="exampleRowMapper" />
You will have to write your exampleRowMapper obviously to reflect the data your fetching. For example:
public class ExampleRowMapper implements ParameterizedRowMapper<String> {
#Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return String.valueOf(rs.getString(1));
}
}
In your dummywriter you add the stepexecution and you will store your value in the step execution context.:
public class DummyItemWriter implements ItemWriter<Object> {
private StepExecution stepExecution;
#Override
public void write(List<? extends Object> item) throws Exception {
ExecutionContext stepContext = this.stepExecution.getExecutionContext();
stepContext.put("someKey", someObject);
}
}
And the bean for the writer:
<bean id="savingDummyWriter" class="your.package.DummyItemWriter" />
And wrap the reader and writer in a step.
<step id="step2">
<tasklet>
<chunk reader="itemReader" writer="dummyItemWriter" commit-interval="1" />
</tasklet>
<listeners>
<listener ref="promotionListener"/>
</listeners>
</step>

Related

Return a JSONObject through Spring MappingJackson2JsonView

I Have xml and json output view for my spring project. I'm using spring 4 version and This is the my ViewResolver xml file.
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
</bean>
<!-- JAXB XML View -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.rest.dto.SportInfoDtoList</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
I want to pass Jackson JSONObject through my controller using ModelAndView.
#RequestMapping(value="stat", method=RequestMethod.POST)
public ModelAndView getSeasonteamStat(#ModelAttribute(value="statDto") StatDto statDto){
ModelAndView model = new ModelAndView();
try{
String seasonteamstatStr = GuideStatClient.getSeasonTeamStats();
JSONObject seasonteamstat = new JSONObject(seasonteamstatStr);
model.addObject("seasonteamstat", seasonteamstat);
return model;
} catch (Exception e){
return model;
}
}
If I return seasonteamstatStr it will return successfully. But I need to pass this string as a json objet. This is a huge object so I dont want to map it into java objects using JAXB.
So is there have any way to pass this string as a json. I tried jackson and gson JSONObject. Thanks in advance
Annotate your method with #ResponseBody which indicates a method return value should be bound to the web response body and change the return type to String

Sending and receiving data in json using spring

I am using POST MAN CLIENT of GOOGLE CHROME TO SEND articleName and articleId AS HEADER application/json.What things I needed to change in my controller and library as well as in my spring servlet.xml?My controller is as follows.
public class ArticleController {
#Autowired
private ArticleService articleService;
Article article = new Article();
Long articleId = article.getArticleId();
#RequestMapping(value = "/save", method = RequestMethod.POST)
public Article saveArticle(#ModelAttribute Article article,
BindingResult bindingresult) {
int a = articleService.addArticle(article);
if (a == 1) {
return new ModelAndView("success");
} else {
return new ModelAndView("error");
}
}
My Spring servlet is:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
<context:component-scan base-package="net.roseindia" />
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<mvc:annotation-driven />
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>net.roseindia.model.Article</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
Plz help me out....Thanks in advance.
I assume what you want is to return JSON easily from Spring.
To do that you need Jackson dependency:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.7.1</version>
</dependency>
When you have it,
you can annotate your method with #ResponseBody annotation just like this:
public #ResponseBody Article saveArticle(#ModelAttribute Article article,
BindingResult bindingresult) {
....
}
Such a method will return JSONified Article object in response.

Spring 3.1 + hibernate 4: Can't get it to run

I tried different configurations but to no effect. The error remained the same. Here the desired config taken from BoneCPs web site:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.2.RELEASE.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.2.RELEASE.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
">
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" autowire-candidate="" autowire="autodetect">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.connection.provider_class">com.jolbox.bonecp.provider.BoneCPConnectionProvider</prop>
<prop key="hibernate.connection.driver_class">org.postgresql.Driver</prop>
<prop key="hibernate.connection.url">jdbc:postgresql:MyDB</prop>
<prop key="hibernate.connection.username">postgres</prop>
<prop key="hibernate.connection.password">123456</prop>
<prop key="bonecp.idleMaxAge">240</prop>
<prop key="bonecp.idleConnectionTestPeriod">60</prop>
<prop key="bonecp.partitionCount">1</prop>
<prop key="bonecp.acquireIncrement">5</prop>
<prop key="bonecp.maxConnectionsPerPartition">60</prop>
<prop key="bonecp.minConnectionsPerPartition">5</prop>
<prop key="bonecp.statementsCacheSize">50</prop>
<prop key="bonecp.releaseHelperThreads">2</prop>
</props>
</property>
</bean>
<!--<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" /> -->
<bean id="AbstractHibernateDAO" abstract="true"
class="org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO"/>
<bean id="ChemicalStructureDAO" extends="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalStructureDAO"/>
<bean id="ChemicalCompoundDAO" extends="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalCompoundDAO"/>
</beans>
And code containing autowired session factory:
#Repository
public abstract class AbstractHibernateDAO< T extends Serializable> {
private final Class< T> clazz;
#Autowired
SessionFactory sessionFactory;
public AbstractHibernateDAO(final Class< T> clazzToSet){
this.clazz = clazzToSet;
}
public T getById(final Long id) {
Preconditions.checkArgument(id != null);
return (T) this.getCurrentSession().get(this.clazz, id);
}
public List< T> getAll() {
return this.getCurrentSession()
.createQuery("from " + this.clazz.getName()).list();
}
public void create(final T entity) {
Preconditions.checkNotNull(entity);
this.getCurrentSession().persist(entity);
}
public void update(final T entity) {
Preconditions.checkNotNull(entity);
this.getCurrentSession().merge(entity);
}
public void delete(final T entity) {
Preconditions.checkNotNull(entity);
this.getCurrentSession().delete(entity);
}
public void deleteById(final Long entityId) {
final T entity = this.getById(entityId);
Preconditions.checkState(entity != null);
this.delete(entity);
}
protected final Session getCurrentSession() {
return this.sessionFactory.getCurrentSession();
}
}
When trying to create a new entity (last line of snippet) I get an error:
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
ChemicalStructureDAO structureDAO = (ChemicalStructureDAO) context.getBean("ChemicalStructureDAO");
ChemicalStructure structure1 = new ChemicalStructure();
structure1.setStructureKey("c1ccccc1");
structure1.setStructureData("c1ccccc1");
structureDAO.create(structure1);
I'm getting a NullPointerException:
java.lang.NullPointerException
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.getCurrentSession(AbstractHibernateDAO.java:78)
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.create(AbstractHibernateDAO.java:54)
at org.bitbucket.myName.moleculedatabaseframework.App.main(App.java:32)
------------------------------------------------------------------------
Maybe I missunderstood what autowired means? I thought that that property will be set automatically. So I tried following:
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
SessionFactory sessionfactory = (SessionFactory)context.getBean("sessionFactory");
ChemicalStructureDAO structureDAO = (ChemicalStructureDAO) context.getBean("ChemicalStructureDAO");
structureDAO.setSessionFactory(sessionfactory);
ChemicalStructure structure1 = new ChemicalStructure();
structure1.setStructureKey("c1ccccc1");
structure1.setStructureData("c1ccccc1");
structureDAO.create(structure1);
This leads to following error:
Exception in thread "main" org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.getCurrentSession(AbstractHibernateDAO.java:78)
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.create(AbstractHibernateDAO.java:54)
I looked at tons of tutorials but they all omit what seems the basic stuff to get things running, eg. ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); does not appear in any spring + hibernate tutorials. Can someone point me at a complete tutorial one that assumes I'm completely dumb and tells me every step required and has an application that actually runs when repeating the code? (yes getting pretty frustrated now. To be honest if I went plain jdbc I would have been up and running hours ago)
Now,how can I get this running? How does autowired work?
EDIT:
THE SOLUTION AS FOUND THROUGH THE HELP OF "Accepted Answer":
The new Spring configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
">
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" autowire="autodetect">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalStructure</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompound</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompoundComposition</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<!-- Spring bean configuration. Tell Spring to bounce off BoneCP -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource">
<ref local="mainDataSource" />
</property>
</bean>
<!-- BoneCP configuration -->
<bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="org.postgresql.Driver" />
<property name="jdbcUrl" value="jdbc:postgresql:MolDB" />
<property name="username" value="postgres"/>
<property name="password" value="123456"/>
<property name="idleConnectionTestPeriod" value="60"/>
<property name="idleMaxAge" value="240"/>
<property name="maxConnectionsPerPartition" value="60"/>
<property name="minConnectionsPerPartition" value="20"/>
<property name="partitionCount" value="3"/>
<property name="acquireIncrement" value="10"/>
<property name="statementsCacheSize" value="50"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<context:annotation-config />
<bean id="AbstractHibernateDAO" abstract="true"
class="org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO"/>
<bean id="ChemicalStructureDAO" parent="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalStructureDAO"/>
<bean id="ChemicalCompoundDAO" parent="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalCompoundDAO"/>
</beans>
I had to add
<context:annotation-config />
to the file and declare the annoted entity classes in sessionFactory configuration:
<property name="annotatedClasses">
<list>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalStructure</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompound</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompoundComposition</value>
</list>
</property>
The I had to uncomment the transaction Manager part and because of that change the data source configuration as the one I used did not work (DataSource is required).
I also had to add
#Repository
#Transactional
public abstract class AbstractHibernateDAO< T extends Serializable> {
//code...
}
to AbstractHibernateDAO. I'm considering to write a blog post and make a link here. For anyone completley new to Spring and hibernate that would be very useful.
Do you have something like this in your spring xml?
<context:annotation-config />
<context:component-scan base-package="base.package" />
This scans for the classes that contains Annotations.

configuring the jacksonObjectMapper not working in spring mvc 3

What I am aiming to do is to configure spring mvc 3 to not return “null” object in json response.
I've asked the question how to configure spring mvc 3 to not return "null" object in json response? . And the suggestion I got is to configure the ObjectMapper, setting the serialization inclusion to JsonSerialize.Inclusion.NON_NULL. So Based on Spring configure #ResponseBody JSON format, I did the following changes in spring config file. But I got the error "Rejected bean name 'jacksonObjectMapper': no URL paths identified org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping:86-AbstractDetectingUrlHandlerMapping.java" during app startup.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<!-- Forwards requests to the "/" resource to the "welcome" view -->
<!--<mvc:view-controller path="/" view-name="welcome"/>-->
<!-- Configures Handler Interceptors -->
<mvc:interceptors>
<!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>
<!-- Saves a locale change using a cookie -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="jacksonSerializationConfig" />
<property name="targetMethod" value="setSerializationInclusion" />
<property name="arguments">
<list>
<value type="org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion">NON_DEFAULT</value>
</list>
</property>
</bean>
<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
I have no idea why it's been rejected. Any suggestion is greatly appreciated!
<mvc:annotation-driven /> and AnnotationMethodHandlerAdapter cannot be used together. (ref: spring forum thread). Possible solution
do not use <mvc:annotation-driven/>. Declaring bean: DefaultAnnotationHandlerMapping
and AnnotationMethodHandlerAdapter and other settings like validation, formatting.
use spring 3.1, which has <mvc:message-converters> (ref: Spring jira)

how to configure spring mvc 3 to not return "null" object in json response?

a sample of json response looks like this:
{"publicId":"123","status":null,"partner":null,"description":null}
It would be nice to truncate out all null objects in the response. In this case, the response would become {"publicId":"123"}.
Any advice? Thanks!
P.S: I think I can do that in Jersey. Also I believe they both use Jackson as the JSON processer.
Added Later:
My configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package="com.SomeCompany.web" />
<!-- Application Message Bundle -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/messages/messages" />
<property name="cacheSeconds" value="0" />
</bean>
<!-- Configures Spring MVC -->
<import resource="mvc-config.xml" />
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<!-- Forwards requests to the "/" resource to the "welcome" view -->
<!--<mvc:view-controller path="/" view-name="welcome"/>-->
<!-- Configures Handler Interceptors -->
<mvc:interceptors>
<!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>
<!-- Saves a locale change using a cookie -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" />
<!--<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="atom" value="application/atom+xml"/>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json"/>
<entry key="xml" value="text/xml"/>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
<bean class="org.springframework.web.servlet.view.xml.MarshallingView" >
<property name="marshaller">
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller" />
</property>
</bean>
</list>
</property>
</bean>
-->
<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
My code:
#Controller
public class SomeController {
#RequestMapping(value = "/xyz", method = {RequestMethod.GET, RequestMethod.HEAD},
headers = {"x-requested-with=XMLHttpRequest","Accept=application/json"}, params = "!closed")
public #ResponseBody
List<AbcTO> getStuff(
.......
}
}
Yes, you can do this for individual classes by annotating them with #JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) or you can do it across the board by configuring your ObjectMapper, setting the serialization inclusion to JsonSerialize.Inclusion.NON_NULL.
Here is some info from the Jackson FAQ: http://wiki.fasterxml.com/JacksonAnnotationSerializeNulls.
Annotating the classes is straightforward, but configuring the ObjectMapper serialization config slightly trickier. There is some specific info on doing the latter here.
Doesn't answer the question but this is the second google result.
If anybody comes here and wants do do it for Spring 4 (as it happened to me), you can use the annotation
#JsonInclude(Include.NON_NULL)
on the returning class.
As mentioned in the comments, and in case anyone is confused, the annotation should be used in the class that will be converted to JSON.
If using Spring Boot for REST, you can do it in application.properties:
spring.jackson.serialization-inclusion=NON_NULL
source
Java configuration for the above. Just place the below in your #Configuration class.
#Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
return builder;
}