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());
Related
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>
I am trying to create rest service using apache camel swagger component.
Now i have this camel context as:
<?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:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<!-- a bean for user services -->
<bean id="personService" class="www.tempuri.person.PersonService"/>
<camelContext id="myCamel" xmlns="http://camel.apache.org/schema/spring">
<restConfiguration component="servlet" bindingMode="auto" contextPath="myService/rest" port="8080">
<dataFormatProperty key="prettyPrint" value="true"/>
</restConfiguration>
<!-- defines the rest services using the context-path /Equipment -->
<rest path="/getPerson/persons" consumes="application/json,application/xml" produces="application/json,application/xml">
<description>Person rest service</description>
<post uri="/search" type="www.tempuri.person.model.GetPerson"
outType="www.tempuri.person.model.GetPerson">
<description>Get Person(s)</description>
<param name="body" type="body" description="Get Person(s)" required="true"/>
<responseMessage code="400" message="Bad Request" />
<responseMessage code="200" message="Person Data" />
<responseMessage code="401" message="Unauthorized" />
<to uri="bean:personService?method=getPersons"/>
</post>
</rest>
</camelContext>
</beans>
And below is my model class GetPerson:
package www.tempuri.person.model;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonRootName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
#ApiModel(description = "Represents Persons")
#XmlRootElement(name="getPerson")
#JsonRootName(value = "getPerson")
public class GetPerson {
#ApiModelProperty(value = "Application Area of GetPerson", required = true)
private ApplicationArea applicationArea;
#ApiModelProperty(value = "Data Area of GetPerson", required = true)
private DataArea dataArea;
/**
* #return the dataArea
*/
public DataArea getDataArea() {
return dataArea;
}
/**
* #param dataArea the dataArea to set
*/
public void setDataArea(DataArea dataArea) {
this.dataArea = dataArea;
}
public ApplicationArea getApplicationArea() {
return applicationArea;
}
public void setApplicationArea(ApplicationArea applicationArea) {
this.applicationArea = applicationArea;
}
}
Now in case of application xml it is working good and the request structure has a root element as getPerson, but in case of JSON Request it doesn't show the root element getPerson. I know that there is something called WRAP_ROOT_VALUE which can be used to enable the root name in case of json. But the problem is i don't know how to do it using camel-config.xml.
How can i set the WRAP_ROOT_VALUE through my camel-config.xml or is there some other way. Thanks in advance..
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);
}
I have given my welcome file in web.xml
But when running the application, it is showing 404 error on http://172.16.2.16:8080/sampletest/
It is a spring application.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>sampletest</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!-- Spring MVC -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
I am using eclipse luna, java 8, tomcat 8 and maven framework.
index.html file is directly under webapp folder and web.xml is under webapp/WEB-INF folder.
If I use index.jsp instead of index.html, it is working. Then welcome page will load using http://172.16.2.16:8080/sampletest/
The issue is only with welcome file. Otherwise spring configuration is working.
http://localhost:8080/sampletest/test/ will load the data from database.
Error log in console
......................
Jul 10, 2014 12:38:42 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 4963 ms
Jul 10, 2014 12:38:42 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/sampletest/] in DispatcherServlet with name 'dispatcher'
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
</body>
</html>
Dispatcher
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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-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/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<context:annotation-config />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<context:component-scan base-package="com.sample.test" />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="packagesToScan">
<array>
<value>com.sample.test.domain</value>
</array>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.use_sql_comments">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.CharSet">UTF-8</prop>
</props>
</property>
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/sampletest?autoConnect=true" />
<property name="user" value="root" />
<property name="password" value="root" />
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- HibernateTransactionManager -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="openSessionInViewInterceptor"
class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
<property name="flushModeName">
<value>FLUSH_AUTO</value>
</property>
</bean>
</beans>
Controller
package com.sample.test.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.sample.test.dto.Response;
import com.sample.test.facade.AccelFlowFacade;
#Controller
public class SampleTestController {
#Autowired
#Qualifier("sampleTestFacade")
SampleTestFacade sampleTestFacade;
public SampleTestFacade getSampleTestFacade() {
return sampleTestFacade;
}
public void setSampleTestFacade(SampleTestFacade sampleTestFacade) {
this.sampleTestFacade= sampleTestFacade;
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
public #ResponseBody Response display() throws Exception {
sampleTestFacade.disaply();
Response res = new Response();
return res;
}
}
Try adding <mvc:default-servlet-handler/> in your dispatcher-servlet.xml.
See here for details.
You have mapped all your incoming requests to the dispatcher here,
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
So all your URL requests for the application goes inside the dispatcher as '/' maps all incoming requests . check for the stacktraces in your application server log
update:
You get the below warning because there are no handler for the '/' pattern,
WARNING: No mapping found for HTTP request with URI [/AccelFlow/] in
DispatcherServlet with name 'dispatcher'
You can do either of below options ,
Map a url with '/' to the controller
Add a specific URL pattern to the spring dispatcher such as .htm or .do as you wish
Modify your web.xml,
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
And in your controller,
#RequestMapping(value = "/test.htm", method = RequestMethod.GET)
public #ResponseBody Response display() throws Exception {
accelFlowFacade.disaply();
Response res = new Response();
return res;
}
At the startup by default all incoming requests are mapping to '/' pattern as you write in the web.xml:
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
update:
Try to map a Controller method for the default view:
#RequestMapping(value = "/", method = GET)
public String welcome() {
return "index";
}
Add viewresolver to dispather-servlet.xml:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/"
p:suffix=".jsp" />
Remove welcome file from the web.xml as automatically spring will search for index page by default:
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
Welcome file can be access using following changes.
change 1. add resource path in dispatcher as following :
<mvc:resources mapping="/" location="/index.html" />
change 2. add controller handler like following :
#Controller
public class RestController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public String welcome() {
return "index.html";
}
}
changes 3: index.html file should be in WebContent folder in project.
Note : If you are not able to add mvc bean in dispatcher servlet file then add
xmlns:mvc="http://www.springframework.org/schema/mvc
in dispatcher servlet config file.
using <mvc:resources mapping="/" location="/index.html" /> is goods for static pages , however changing it to
#RequestMapping(value = "/", method = RequestMethod.GET)
public String welcome() {
return "index.html";
}
is not good design as all model in other controllers may point back to index page, instead use
<mvc:resources mapping="/" location="/redfresh.html" />
and make refresh page such
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="refresh" content="0;URL='/index'" />
</head>
<body>
</body>
</html>
and point in controller to index such:
#Controller
public class indexPageController {
#RequestMapping(value = "/index", method = RequestMethod.GET, produces = "text/html")
public String index() {
return "index";
}
}
Just add your index.html to webContent folder. Because welcome file is searched in that folder itself.
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