Kundera Redis plugin returns empty list on query - kundera

I am trying to resolve a problem where I cannot return a list with Kundera query for redis back end. I have problem returning a single entity and no problem persistening entities. However when I try to do a simple select to return a single type it always returns me an empty list.
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
https://raw.github.com/impetus-opensource/Kundera/Kundera-2.0.4/kundera-core/src/test/resources/META-INF/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="redis_pu">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<class>com.factory.ng.api.domain.DomainEntity</class>
<class>com.factory.ng.api.domain.Factory</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="kundera.show.query" value="true" />
<property name="kundera.nodes" value="localhost" />
<property name="kundera.port" value="6379" />
<property name="kundera.keyspace" value="RedisK" />
<property name="kundera.dialect" value="redis" />
<property name="kundera.client" value="redis" />
<property name="kundera.client.lookup.class" value="com.impetus.client.redis.RedisClientFactory" />
<property name="kundera.transaction.resource.class" value="com.impetus.client.redis.RedisTransaction" />
<property name="kundera.indexer.class" value="com.impetus.client.redis.RedisIndexer" />
</properties>
</persistence-unit>
...
Here is the entity that I am trying to retrieve.
#Entity
#XmlRootElement
public class Factory extends DomainEntity implements IHasSlots {
/**
* Serialization Id
*/
private static final long serialVersionUID = 7829467874878679280L;
private String name;
private List<Line> lines;
public Factory() {
this(null);
}
public Factory(String name) {
this(name, new ArrayList<Line>());
}
public Factory(String name, Collection<Line> lines) {
this(name, new ArrayList<Line>(lines));
}
...
This unit test always ends with an assert error that the list is empty.
#Test
public void testList() {
EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("redis_pu");
EntityManager em = emFactory.createEntityManager();
List<Factory> factories = em.createQuery("SELECT e FROM Factory e").getResultList();
//Collection<Factory> factories = factoryDao.list();
Assert.assertTrue(factories.size() > 0);
}

Related

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

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>

Why is my EclipseLink Query Results Cache NOT working

I am developing a website on TomEE, and I want to use the EclipseLink Query Results Cache (L2) working, but every time I reload my web page, SELECT query is running (checked via general_log of mysql).
My Database entity looks like below:
#Entity(name="item")
#NamedQueries({
#NamedQuery(name="ItemEntity.getAllList",
query="Select distinct itemEntity from mypackage.entity.ItemEntity itemEntity",
hints={
#QueryHint(name="eclipselink.query-results-cache", value="true"),
#QueryHint(name="eclipselink.query-results-cache.size", value="1000"),
#QueryHint(name="eclipselink.query-results-cache.expiry", value="10000"), //10 secs for test but not working
#QueryHint(name="eclipselink.query-results-cache.type", value="FULL")
}
)
})
#org.eclipse.persistence.annotations.Cache(
type= CacheType.FULL,
size=10000,
expiry=60000, // 1 minute for test
coordinationType= CacheCoordinationType.INVALIDATE_CHANGED_OBJECTS
)
public class ItemEntity implements Serializable, Comparable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name="name", unique=true, nullable=false)
private String name;
/* getters and setters for fields */
public CompanyEntity(){}
#Override
public int compareTo(Object o) {.......}
}
My persistence.xml looks like below:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="myprojectname-persistence-unit" transaction-type="JTA">
<jta-data-source>myprojectname-mysql-jdbc-jta-resource</jta-data-source>
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<properties>
<property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.MySQLPlatform"/>
<property name="eclipselink.cache.shared.default" value="true"/>
</properties>
</persistence-unit>
</persistence>
I read database table like below:
#Stateful
public class CompanyDao {
#PersistenceContext(unitName = "myprojectname-persistence-unit", type = PersistenceContextType.EXTENDED)
protected EntityManager em;
public List<CompanyEntity> getAllList(){
return this.em.createNamedQuery("ItemEntity.getAllList", ItemEntity.class).getResultList();
}
}
Dependency version details:
TomEE 1.7.2, Java EE6, openJPA 2.4.0, openEJB Java EE API 6.0-6, openEJB core 4.7.2, EclipseLink 2.6.2, MySQL 5.6.23, MySQL connector/J 5.1.38 (Tomcat connection pool)
I've looked at a similar question:
Can't get Eclipselink level 2 cache to work
but it doesn't describe how the OP managed to cache query results.
BTW, the default cache (L2), with em.find(ItemEntity.class, id); is working just fine.
What am I missing? Please help me out.
Solved.
I was using EclipseLink 2.6.2, I downgraded to version 2.4.2, and now Query Results Cache WORKS as expected!
I guess EclipseLink 2.6.x or 2.5.x is not quite compatible with JPA 2.0.x.
It's confusing, because when I use 2.5.x or higher, those still seem to be working, BESIDES the feature of Query Results Cache.
My persistence.xml looks like bellow now, so I can get log output:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="myprojectname-persistence-unit" transaction-type="JTA">
<jta-data-source>myprojectname-mysql-jdbc-jta-resource</jta-data-source>
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<properties>
<property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.MySQLPlatform"/>
<property name="eclipselink.logging.logger" value="JavaLogger"/>
<!-- The warning log of "Problem while registering MBean: java.lang.NullPointerException" did not go away even if I set bellow 2 propertes -->
<!--
<property name="eclipselink.register.dev.mbean" value="false" />
<property name="eclipselink.register.run.mbean" value="false" />
-->
<property name="eclipselink.cache.shared.default" value="true"/>
<property name="eclipselink.logging.parameters" value="true"/>
<property name="eclipselink.logging.timestamp" value="true"/>
<property name="eclipselink.logging.session" value="true"/>
<property name="eclipselink.logging.thread" value="true"/>
<property name="eclipselink.logging.exceptions" value="true"/>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
</persistence-unit>
</persistence>

Why jackson formats date to yyyy-MM-dd instead of timestamp?

I have my first spring project with a rest service.
Only one problem I cannot solve myself. My "get" request gives the objects date value this way:
{"id":6,"type":"Trainer","changed":"2015-06-20","created":"2015-06-19"}
but I want it in timestamp format, as I thought was the default.
The input dates in my PUT request are parsed from timestamp format as expected.
I am using springframework 4.1.6.RELEASE and fasterxml.jackson 2.5.4
with these spring artifacts: spring-context, spring-webmvc, spring-jdbc
and these fasterxml artifacts: jackson-core, jackson-databind
This is my Controller method:
#Override
#RequestMapping(value="/{id}", method=RequestMethod.GET)
#ResponseBody
public T getObject(#PathVariable("id") long id) {
T obj = dao.getById(id);
logger.debug("GET " + getClass().getSimpleName() + "." + id + ": " + obj);
return obj;
}
My web.xml:
<?xml
version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/servlet-context.xml
classpath:Beans.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
servlet-context.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="de.kreth.clubhelperbackend" />
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/" />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="2" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
and my Beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/clubhelperbackend" />
<property name="username" value="markus" />
<property name="password" value="0773" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<bean id="sqlForDialect" class="de.kreth.clubhelperbackend.SqlForMysql">
<constructor-arg ref="jdbcTemplate" />
</bean>
<bean id="personDao" class="de.kreth.clubhelperbackend.dao.PersonDao">
<property name="sqlDialect" ref="sqlForDialect" />
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
<bean id="dbcheckAspect" class="de.kreth.clubhelperbackend.aspects.MysqlDbCheckAspect">
<constructor-arg ref="dataSource" />
</bean>
<!-- <bean id="logger" class="de.kreth.clubhelperbackend.aspects.LoggerAspect" /> -->
<aop:aspectj-autoproxy>
<aop:include name="dbcheckAspect" />
<!-- <aop:include name="logger"/> -->
</aop:aspectj-autoproxy>
</beans>
So, how can I get the json date output in general as a timestamp?
Please note, that I don't want to change the data classes (getters) as they are generated from another project.
--- Edit:
The Person Model:
public class Person implements java.io.Serializable, Data {
private static final long serialVersionUID = -2810735258874241724L;
private Long id;
private String type;
/** Not-null value. */
private java.util.Date changed;
/** Not-null value. */
private java.util.Date created;
public Person() {
}
public Person(Long id) {
this.id = id;
}
public Person(Long id, String type,java.util.Date changed, java.util.Date created) {
this.id = id;
this.type = type;
this.changed = changed;
this.created = created;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
/** Not-null value. */
public java.util.Date getChanged() {
return changed;
}
/** Not-null value; ensure this value is available before it is saved to the database. */
public void setChanged(java.util.Date changed) {
this.changed = changed;
}
/** Not-null value. */
public java.util.Date getCreated() {
return created;
}
#Override
public void setCreated(Date created) {
this.created = created;
}
}
The date interface:
package de.kreth.clubhelperbackend.pojo;
import java.util.Date;
public interface Data {
public Long getId() ;
public void setId(Long id);
public Date getChanged();
public void setChanged(Date changed);
public Date getCreated();
public void setCreated(Date created);
}
According Jackson docs, Jackson should use timestamps in miliseconds by default.
So I see two options. One is that your date format is enforced by #JsonFormat annotation on your date field as #beerbajay mentioned in his comment.
Second option is that somebody configured custom ObjectMapper for your MappingJacksonHttpMessageConverter. Such example configuration is in this SO answer. I would try to find it in your application and talk to the teammate that introduced it why it's needed.
If such custom ObjectMapper isn't configured, it's strange, but at least you can try to explicitly configure SerializationConfig.getDateFormat as WRITE_DATES_AS_TIMESTAMPS to true.
I think Jackson treats java.util.Date and java.sql.Date differently. Even though the later is actually a subclass of the former, Jackson assumes both classes are totally different.
So, if you don't want the value to be converted to 'yyyy-MM-dd', ensure that it is not a java.sql.Date object.
For example:
class Student {
private java.util.Date birthDate;
// getter and setter
}
Student san = new Student();
// Then JSON converted to: 'yyyy-MM-dd' format
san.setBirthDate(new java.sql.Date(System.currentTimeMillis()));
// Then JSON converted to: timestamp format or according to #JsonFormat format
san.setBirthDate(new java.util.Date());

Test Camel Integration with JUnit

I have a Camel integration flow. At one point, there is client creation, which is as following configuration:
<routeContext id="clientCreation" xmlns="http://camel.apache.org/schema/spring">
<route customId="true" id="clientCreationRouter">
<from uri="direct:client-creation-start" customId="true" id="Client-Creation-Initiator"/>
<bean ref="clientCreationService" method="constructClientDto" />
<bean ref="clientCreationService" method="populateClientRequestMessage" />
<bean ref="clientCreationService" method="saveClientDetails" />
<bean ref="clientCreationService" method="createClientCreationFixedLengthMessage" />
<setHeader headerName="flow-status" customId="true" id="Client-Creation-Update-Header">
<simple>CLIENT_CREATED</simple>
</setHeader>
</route>
</routeContext>
ConstructClientDto has FlowInfo object as the input.
createClientCreationFixedLengthMessage has a String as the output. I want to test this part of the flow. Basically, I want to provide a FlowInfo object which is ready for Client-Creation and then see whether this part of the integration is successful based on the result provided at the end.
So far, this is what I tried:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration (locations={"/META-INF/spring/data-extractor.xml",
"/META-INF/spring/data-splitter.xml",
"/META-INF/spring/client-creation.xml"})
public class ClientCreationFlowTest extends CamelTestSupport{
#Produce (uri = "direct:client-creation-start")
protected ProducerTemplate template;
#EndpointInject(uri = "mock:result")
protected MockEndpoint resultEndpoint;
#Autowired
FlowRepository repository;
#Test
public void testClientCreation () throws Exception {
FlowInfo flowInfo = repository.findById("1234");
template.sendBody(resultEndpoint, flowInfo);
}
}
When I run the test case, I get success. But when I debugged it, it does not seemed to be running through ClientCreationService. I am very new to Camel and the task is critical. Any help would be appreciated.
First, in your route definition you must send the result to mock:result at the end:
<routeContext id="clientCreation" xmlns="http://camel.apache.org/schema/spring">
<route customId="true" id="clientCreationRouter">
<from uri="direct:client-creation-start" customId="true" id="Client-Creation-Initiator"/>
<bean ref="clientCreationService" method="constructClientDto" />
<bean ref="clientCreationService" method="populateClientRequestMessage" />
<bean ref="clientCreationService" method="saveClientDetails" />
<bean ref="clientCreationService" method="createClientCreationFixedLengthMessage" />
<setHeader headerName="flow-status" customId="true" id="Client-Creation-Update-Header">
<simple>CLIENT_CREATED</simple>
</setHeader>
<to uri="mock:result"/>
</route>
</routeContext>
Second, in your JUnit test class you must not send the message to the mock endpoint but to direct:client-creation-start which is automatically done as the template is autowired with this uri:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration (locations={"/META-INF/spring/data-extractor.xml",
"/META-INF/spring/data-splitter.xml",
"/META-INF/spring/client-creation.xml"})
public class ClientCreationFlowTest extends CamelTestSupport{
#Produce(uri = "direct:client-creation-start")
protected ProducerTemplate template;
#EndpointInject(uri = "mock:result")
protected MockEndpoint resultEndpoint;
#Autowired
FlowRepository repository;
#Test
public void testClientCreation () throws Exception {
FlowInfo flowInfo = repository.findById("1234");
resultEndpoint.expectedBodiesReceived("my string output");
template.sendBody(flowInfo);
resultEndpoint.assertIsSatisfied();
}
}
Try template.sendBody(flowInfo); instead of directly sending it to the result endpoint, which bypasses your whole route.

Spring REST: HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8'

I am getting the above error, due to a problem with Jackson attempting to deserialize my POJO.
I've debugged the code and it returns false within Jackson's ObjectMapper:
public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
JavaType javaType = getJavaType(type, contextClass);
return (this.objectMapper.canDeserialize(javaType) && canRead(mediaType));
}
this.objectMapper.canDeserialize(javaType) returns false which causes the error
My Controller is as follows:
#Controller
public class CancelController {
#Autowired
private CancelService cancelService;
#RequestMapping( value="/thing/cancel", method=RequestMethod.POST, consumes="application/json" )
public #ResponseBody CancelThingResponseDTO cancelThing(#RequestBody CancelRequestDTO cancelThingRequest) {
return cancelService.cancelThing(cancelThingRequest);
}
My CancelRequestDTO implements Serializable:
public class CancelRequestDTO implements Serializable{
/**
* Default serialization ID
*/
private static final long serialVersionUID = 1L;
/**
* Reason code associated with the request
*/
private final String reasonCode;
/**
* Identifier of the entity associated with the request
*/
private final EntityIdentifier entityIdentifier;
/**
* Default constructor
*
* #param reasonCode Reason code associated with the request
* #param entityIdentifier Identifier of the entity associated with the request
*/
public CancelRequestDTO(String reasonCode, EntityIdentifier entityIdentifier) {
super();
this.reasonCode = reasonCode;
this.entityIdentifier = entityIdentifier;
}
/**
* #return Returns the reasonCode.
*/
public String getReasonCode() {
return reasonCode;
}
/**
* #return Returns the entityIdentifier.
*/
public EntityIdentifier getEntityIdentifier() {
return entityIdentifier;
}
}
My Spring configuration is as follow:
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<mvc:annotation-driven />
<!-- Scan for stereotype annotations -->
<context:component-scan base-package="com.cancel.web.controller" />
<bean id="viewNameTranslator"
class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator" />
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean id="jsonView"
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" >
<property name="contentType" value="application/json;charset=UTF-8"/>
</bean>
<!-- Register JSON Converter for RESTful Web Service -->
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
</bean>
</list>
</property>
</bean>
Anyone know what might be causing this deserialization issue?
Thanks
Caused by my DTO not having a default constructor with setters! So looks like an inaccurate Exception from Jackson
For anyone who still facing this problem, you cannot have two #JsonBackReference in a single class, add value to one of the reference like this #JsonBackReference(value = "secondParent") also add the same value to #JsonManagedReference(value ="secondParent") in parent class.
I have always done this using the ContentNegotiatingViewResolver. It seems that it is not understanding the content type that you are passing it. This is the configuration that I typically use for doing what you are trying to do:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="contentNegotiationManager">
<bean class="org.springframework.web.accept.ContentNegotiationManager">
<constructor-arg>
<bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
<constructor-arg>
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true" />
</bean>
</constructor-arg>
</bean>
</list>
</property>
</bean>
This video goes through doing exactly what you are trying to do with consuming the service through jQuery in the UI:
http://pluralsight.com/training/Courses/TableOfContents/springmvc-intro