I am trying to create a spring rest service. My servlet.xml is like following:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<!-- Database Configuration -->
<import resource="classpath:DataSource.xml"/>
<import resource="classpath:Hibernate.xml"/>
<!-- Beans Declaration -->
<import resource="classpath:Employee.xml"/>
<context:component-scan base-package="com.nilenium.service.controller" />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter"/>
<ref bean="marshallingHttpMessageConverter"/>
</list>
</property>
</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true"/>
<property name="annotatedClasses">
<list>
<value>com.nilenium.employee.model.Employee</value>
<value>com.nilenium.employee.model.EmployeeRecord</value>
</list>
</property>
</bean>
<bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="xstreamMarshaller"/>
<property name="unmarshaller" ref="xstreamMarshaller"/>
</bean>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="ignoreAcceptHeader" value="true" />
<property name="defaultContentType" value="application/json" />
<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.MappingJacksonJsonView" />
<!-- XML View -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true"/>
<property name="aliases">
<props>
<prop key="employee">com.nilenium.employee.model.Employee</prop>
<prop key="employee">com.nilenium.employee.model.EmployeeRecord</prop>
</props>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
</bean>
</beans>
And my model class is like this:
package com.nilenium.employee.model;
import java.io.Serializable;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonRootName;
import com.thoughtworks.xstream.annotations.XStreamAlias;
#XStreamAlias("employee")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private int employeeId;
private String employeeName;
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public Employee(int employeeId, String employeeName)
{
this.employeeId = employeeId;
this.employeeName = employeeName;
}
public Employee() {
}
}
My service controller class is like this:
package com.nilenium.service.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.nilenium.employee.bo.EmployeeBo;
import com.nilenium.employee.model.Employee;
import com.nilenium.employee.model.EmployeeRecord;
#Controller
#RequestMapping("/Service")
public class NileniumServiceController {
#Autowired
private EmployeeBo employeeBo;
#ExceptionHandler
public String exceptionHandler(Exception e){
return "serviceError";
}
#RequestMapping(value = "employeeId/{employeeId}", method = RequestMethod.GET, headers = "Accept=application/xml, application/json")
public Employee getEmployeeName(#PathVariable int employeeId,
HttpServletResponse resp,
ModelMap model) {
// System.out.println("Emp Name : " + employeeName);
Employee empReturned = new Employee();
empReturned.setEmployeeId(employeeId);
empReturned.setEmployeeName("Demo Name");
return empReturned;
}
#RequestMapping(value = "/employees", method = RequestMethod.GET, headers = "Accept=application/xml, application/json")
public EmployeeRecord getAllEmployeeDetails(HttpServletResponse resp,
ModelMap model) {
List<Employee> empListReturned = employeeBo.getAllEmployee();
EmployeeRecord eRecords = new EmployeeRecord();
eRecords.setEmployeeList(empListReturned);
return eRecords;
}
#RequestMapping(value = "/storeemployee",method = RequestMethod.POST, headers = {"Accept=text/xml, application/json"})
public Employee storeEmpRecord(#RequestBody Employee employee,HttpServletResponse resp,
ModelMap model)
{
System.out.println("Emp Id received : "+employee.getEmployeeId());
System.out.println("Emp Name received : "+employee.getEmployeeName());
// Employee empReturned = employeeBo.findByEmployeeId(1);
return employee;
}
}
When I am trying to post an xml to the storeEmpRecord method xstream marshaller is not able to convert the xml request to respective object (Employee object).
My test client is like this:
package com.nilenium.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry;
import com.nilenium.employee.model.Employee;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
public class RestPostTest {
public static void main(String[] args) {
Employee emp = new Employee();
emp.setEmployeeId(1);
emp.setEmployeeName("Nilalohita");
XStream xStream = new XStream(new DomDriver());
xStream.alias("employee", Employee.class);
System.out.println(xStream.toXML(emp));
String xmlBody = xStream.toXML(emp);
HttpClient client = new DefaultHttpClient();
String jsonDemo = "{\"employeeId\":2,\"employeeName\":\"He-Man\"}";
try {
HttpPost post = new HttpPost("http://localhost:8080/SampleMaven/Service/storeemployee");
// post.addHeader("Accept", "application/json");
// post.addHeader("Content-Type", "application/json");
post.addHeader("Accept", "application/xml");
post.addHeader("Content-Type", "application/xml");
StringEntity entity = new StringEntity(xmlBody, "UTF-8");
// entity.setContentType("application/json");
entity.setContentType("application/xml");
post.setEntity(entity);
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Please let me know if i am doing something wrong. The same thing is working for jaxb using #XMLroot for Employee class instead of #XStreamAlias("employee").
I am getting the following error. the full stack trace is like this
Caused by:</h3><pre>javax.servlet.ServletException: Unable to locate object to be marshalled in model: {}
at org.springframework.web.servlet.view.xml.MarshallingView.renderMergedOutputModel(MarshallingView.java:100)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1047)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:817)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:726)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:206)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:648)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:205)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
The problem is in the controller method :
#RequestMapping(value = "/storeemployee",method = RequestMethod.POST, headers = {"Accept=text/xml, application/json"})
public Employee storeEmpRecord(#RequestBody Employee employee,HttpServletResponse resp,
ModelMap model)
{
System.out.println("Emp Id received : "+employee.getEmployeeId());
System.out.println("Emp Name received : "+employee.getEmployeeName());
// Employee empReturned = employeeBo.findByEmployeeId(1);
return employee;
}
Spring MVC does not (cannot) add objects to model automatically. You need to add the employee object to the ModelMap. The model map is then passed to the marshaling view, which looks for any objects that it can marshal, and marshals them to response.
Unable to locate object to be marshalled in model: {} Means the Marshalling View received a ModelMap with no objects that have the XStream annotations.
Hope this helps.
Related
When you start tomcat,
it consumes 70mbs of memory,
when I make requests then it consumes 80mbs,
never back to 70mbs
Crud code
package br.com.controlevendas.recurso;
import java.io.IOException;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import br.com.controlevendas.controle.ClienteControle;
import br.com.controlevendas.modelo.Cliente;
#Component
#Path("/cliente")
public class ClienteRecurso {
#Autowired
private ClienteControle clienteControle;
#GET
#Path("/lista")
#Produces(MediaType.APPLICATION_JSON)
public List<Cliente> listar() {
List<Cliente> clienteList = this.clienteControle.listar();
try {
this.clienteControle.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return clienteList;
}
#POST
#Path("")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Cliente inserir(Cliente cliente) {
cliente = this.clienteControle.salvar(cliente);
try {
this.clienteControle.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return cliente;
}
#PUT
#Path("")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Cliente alterar(Cliente cliente) {
cliente = this.clienteControle.alterar(cliente);
try {
this.clienteControle.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return cliente;
}
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Cliente buscar(#PathParam("id") Integer id) {
Cliente cliente = new Cliente();
cliente.setIdcliente(id);
cliente = this.clienteControle.buscar(cliente);
try {
this.clienteControle.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return cliente;
}
#DELETE
#Path("/{id}")
public void remover(#PathParam("id") Integer id) {
Cliente cliente = new Cliente();
cliente.setIdcliente(id);
cliente = this.clienteControle.remover(cliente);
try {
this.clienteControle.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ClienteControle
package br.com.controlevendas.controle;
import java.io.Closeable;
import java.util.List;
import br.com.controlevendas.modelo.Cliente;
public interface ClienteControle extends Closeable {
Cliente salvar(Cliente cliente);
Cliente alterar(Cliente cliente);
Cliente remover(Cliente cliente);
Cliente buscar(Cliente cliente);
List<Cliente> listar();
}
ClienteControleImplementacao
package br.com.controlevendas.controle.implementacao;
import java.io.IOException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import br.com.controlevendas.controle.ClienteControle;
import br.com.controlevendas.dao.ClienteDAO;
import br.com.controlevendas.modelo.Cliente;
#Service
public class ClienteControleImplementacao implements ClienteControle {
#Autowired
private ClienteDAO clienteDAO;
#Override
public void close() throws IOException {
this.clienteDAO.close();
}
#Transactional(propagation = Propagation.REQUIRED)
#Override
public Cliente salvar(Cliente cliente) {
return this.clienteDAO.salvar(cliente);
}
#Transactional(propagation = Propagation.REQUIRED)
#Override
public Cliente alterar(Cliente cliente) {
return this.clienteDAO.alterar(cliente);
}
#Override
public Cliente buscar(Cliente cliente) {
return this.clienteDAO.buscar(cliente);
}
#Override
public List<Cliente> listar() {
return this.clienteDAO.listar();
}
#Transactional(propagation = Propagation.REQUIRED)
#Override
public Cliente remover(Cliente cliente) {
return this.clienteDAO.remover(cliente);
}
}
ClienteDAO
package br.com.controlevendas.dao;
import java.io.Closeable;
import java.util.List;
import br.com.controlevendas.modelo.Cliente;
public interface ClienteDAO extends Closeable {
Cliente salvar(Cliente cliente);
Cliente alterar(Cliente cliente);
Cliente remover(Cliente cliente);
Cliente buscar(Cliente cliente);
List<Cliente> listar();
}
ClienteDAOImplementacao
package br.com.controlevendas.dao.implementacao;
import java.io.IOException;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;
import br.com.controlevendas.dao.ClienteDAO;
import br.com.controlevendas.modelo.Cliente;
#Repository
public class ClienteDAOImplementacao implements ClienteDAO {
#PersistenceContext
private EntityManager entityManager;
#Override
public Cliente salvar(Cliente cliente) {
this.entityManager.persist(cliente);
return cliente;
}
#Override
public Cliente alterar(Cliente cliente) {
return this.entityManager.merge(cliente);
}
#Override
public Cliente buscar(Cliente cliente) {
Query query = this.entityManager.createQuery("from Cliente where idcliente = ?");
query.setParameter(1, cliente.getIdcliente());
return (Cliente) query.getSingleResult();
}
#SuppressWarnings("unchecked")
#Override
public List<Cliente> listar() {
Query query = this.entityManager.createQuery("from Cliente");
return query.getResultList();
}
#Override
public void close() throws IOException {
this.entityManager.close();
}
#Override
public Cliente remover(Cliente cliente) {
cliente = this.entityManager.getReference(Cliente.class, cliente.getIdcliente());
this.entityManager.remove(cliente);
return cliente;
}
}
persistence.xml
<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
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="controlevendas">
<!-- provedor/implementacao do JPA -->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
</persistence-unit>
</persistence>
WebContent/META-INF/context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context reladable="true">
<Resource
name="jdbc/vendas"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="60"
username="root"
password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost/controlevendas"/>
</Context>
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:annotation-config />
<context:component-scan base-package="br.com.controlevendas.controle.implementacao" />
<context:component-scan base-package="br.com.controlevendas.dao.implementacao" />
<context:component-scan base-package="br.com.controlevendas.recurso" />
<!-- <bean id="dataSourceMySQL" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> -->
<!-- <property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost/controlevendas" />
<property name="user" value="root" />
<property name="password" value="root" />
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxStatements" value="50" />
<property name="checkoutTimeout" value="3000" />
<property name="idleConnectionTestPeriod" value="3000" />
<property name="maxIdleTime" value="180" />
<property name="numHelperThreads" value="5" />
<property name="acquireIncrement" value="1" />
<property name="acquireRetryAttempts" value="5" /> -->
<!-- </bean> -->
<bean id="dataSource.jndi" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton" lazy-init="true">
<property name="jndiName" value="java:comp/env/jdbc/vendas" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- <property name="dataSource" ref="dataSourceMySQL" /> -->
<property name="dataSource" ref="dataSource.jndi" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
<prop key="hibernate.jdbc.use_streams_for_binary">true</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
<prop key="hibernate.connection.release_mode">after_transaction</prop>
<prop key="hibernate.jdbc.use_get_generated_keys">true</prop>
<prop key="hibernate.statement_cache.size">0</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
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_3_0.xsd" version="3.0">
<display-name>ControleVendas</display-name>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>jersey-spring</servlet-name>
<servlet-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>br.com.controlevendas.recurso</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-spring</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<resource-ref>
<description>DataSource Vendas</description>
<res-ref-name>jdbc/vendas</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<session-config>
<session-timeout>1</session-timeout>
</session-config>
</web-app>
hibernate 4.3.8
spring 4.14
jersey 1.18
jackson 1.9.13
Someone help with any tips?
I am trying to get my Spring rest controller to return jsonp but I am having no joy
The exact same code works ok if I want to return json but I have a requirement to return jsonp
I have added in a converter I found source code for online for performing the jsonp conversion
I am using Spring version 4.1.1.RELEASE and Java 7
Any help is greatly appreciated
Here is the code in question
mvc-dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="parameterName" value="mediaType" />
<property name="ignoreAcceptHeader" value="false"/>
<property name="useJaf" value="false"/>
<property name="defaultContentType" value="application/json" />
<property name="mediaTypes">
<map>
<entry key="atom" value="application/atom+xml" />
<entry key="html" value="text/html" />
<entry key="jsonp" value="application/javascript" />
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml"/>
</map>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="contentNegotiationManager" ref="contentNegotiationManager" />
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/templates/slim/${views.template.directory}/" />
<property name="suffix" value=".jsp" />
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="com.webapp.handler.MappingJacksonJsonpView" />
</list>
</property>
</bean>
</beans>
com.webapp.handler.MappingJacksonJsonpView
package com.webapp.handler;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
public class MappingJacksonJsonpView extends MappingJackson2JsonView {
/** Local log variable. **/
private static final Logger LOG = LoggerFactory.getLogger(MappingJacksonJsonpView.class);
/**
* Default content type. Overridable as bean property.
*/
public static final String DEFAULT_CONTENT_TYPE = "application/javascript";
#Override
public String getContentType() {
return DEFAULT_CONTENT_TYPE;
}
/**
* Prepares the view given the specified model, merging it with static
* attributes and a RequestContext attribute, if necessary.
* Delegates to renderMergedOutputModel for the actual rendering.
* #see #renderMergedOutputModel
*/
#Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
LOG.info("Entered render Method :{}", request.getMethod());
if("GET".equals(request.getMethod().toUpperCase())) {
LOG.info("Request Method is a GET call");
Map<String, String[]> params = request.getParameterMap();
if(params.containsKey("callback")) {
String callbackParam = params.get("callback")[0];
LOG.info("callbackParam:{}", callbackParam);
response.getOutputStream().write(new String(callbackParam + "(").getBytes());
super.render(model, request, response);
response.getOutputStream().write(new String(");").getBytes());
response.setContentType(DEFAULT_CONTENT_TYPE);
}
else {
LOG.info("Callback Param not contained in request");
super.render(model, request, response);
}
}
else {
LOG.info("Request Method is NOT a GET call");
super.render(model, request, response);
}
}
}
Controller Method In Question
#RequestMapping(value = { "/sources"}, method = RequestMethod.GET,
produces={MediaType.ALL_VALUE,
"text/javascript",
"application/javascript",
"application/ecmascript",
"application/x-ecmascript",
"application/x-javascript",
MediaType.APPLICATION_JSON_VALUE})
#ResponseBody
public Object getSources(#PathVariable(value = API_KEY) String apiKey,
#RequestParam(value = "searchTerm", required = true) String searchTerm,
#RequestParam(value = "callBack", required = false) String callBack) {
LOG.info("Entered getSources - searchTerm:{}, callBack:{} ", searchTerm, callBack);
List<SearchVO> searchVOList = myServices.findSources(searchTerm);
if (CollectionUtils.isEmpty(searchVOList)) {
LOG.error("No results exist for the searchterm of {}", searchTerm);
return searchVOList;
}
LOG.debug("{} result(s) exist for the searchterm of {}", searchVOList.size(), searchTerm);
LOG.info("Exiting getSources");
return searchVOList;
}
**Jquery Ajax Code **
$.ajax({
type: "GET",
url: "http://localhost:8080/my-web/rest/sources,
data: {
"searchTerm": request.term
},
//contentType: "application/json; charset=utf-8",
//dataType: "json",
contentType: "application/javascript",
dataType: "jsonp",
success: function(data) {
alert("success");
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("Failure");
}
});
A snippet of the error stacktrace that I get is as follows
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:168) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:101) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:198) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71) ~[spring-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:122) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620) [servlet-api.jar:na]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) [servlet-api.jar:na]
As stated on the spring.io blog regarding the Spring 4.1 release:
JSONP is now supported with Jackson. For response body methods declare
an #ControllerAdvice as shown below. For View-based rendering simply
configure the JSONP query parameter name(s) on
MappingJackson2JsonView.
#ControllerAdvice
private static class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
super("callback");
}
}
[...] In 4.1 an #ControllerAdvice can also implement
ResponseBodyAdvice in which case it will be called after the
controller method returns but before the response is written and
therefore committed. This has a number of useful applications with
#JsonView the JSONP already serving as two examples built on it.
Javadoc taken from MappingJackson2JsonView:
Set JSONP request parameter names. Each time a request has one of those
parameters, the resulting JSON will be wrapped into a function named as
specified by the JSONP request parameter value.
The parameter names configured by default are "jsonp" and "callback".
You don't need to implement this stuff by yourself. Just reuse the bits from the Spring Framework.
Spring Boot example
Following simple Spring Boot application demonstrates use of build in JSONP support in Spring MVC 4.1.
Example requires at least Spring Boot 1.2.0.RC1.
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;
import java.util.Collections;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
#RestController
#SpringBootApplication
class Application {
#JsonAutoDetect(fieldVisibility = ANY)
static class MyBean {
String attr = "demo";
}
#ControllerAdvice
static class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
super("callback");
}
}
#Bean
public HttpMessageConverters customConverters() {
return new HttpMessageConverters(false, Collections.<HttpMessageConverter<?> >singleton(new MappingJackson2HttpMessageConverter()));
}
#RequestMapping
MyBean demo() {
return new MyBean();
}
#RequestMapping(produces = APPLICATION_JSON_VALUE)
String demo2() {
return "demo2";
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
URL http://localhost:8080/demo?callback=test converts a POJO into a JSONP response:
test({"attr":"demo"});
URL http://localhost:8080/demo2?callback=test converts a String into a JSONP response:
test("demo2");
I am trying to link my ContactService to my ContactDao so that it can be retrieved from the database and then consumed by a REST Client but I receive the following error when running the REST Client:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:64)
at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:685)
at com.aucklanduni.spring.webservices.service.ContactDaoImpl.findAll(ContactDaoImpl.java:40)
at com.aucklanduni.spring.webservices.service.ContactServiceMockImplementation.findAll(ContactServiceMockImplementation.java:56)
at com.aucklanduni.spring.webservices.restful.controller.ContactController.listData(ContactController.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:685)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:919)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:851)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:844)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Here is my RestClientMain:
package com.aucklanduni.spring.webservices.restful;
import java.util.Date;
import org.joda.time.DateTime;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.web.client.RestTemplate;
import com.aucklanduni.spring.webservices.domain.Contact;
import com.aucklanduni.spring.webservices.domain.Contacts;
import com.aucklanduni.spring.webservices.service.ContactDao;
public class RestfulClientMain {
private static final String URL_GET_ALL_CONTACTS = "http://localhost:8080/Contact/contacts";
private static final String URL_GET_CONTACT_BY_ID = "http://localhost:8080/Contact/contacts/{id}";
private static final String URL_CREATE_CONTACT = "http://localhost:8080/Contact/contacts/";
private static final String URL_UPDATE_CONTACT = "http://localhost:8080/Contact/contacts/{id}";
private static final String URL_DELETE_CONTACT = "http://localhost:8080/Contact/contacts/{id}";
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:restful-client-app-context.xml");
ctx.refresh();
Contacts contacts;
Contact contact;
RestTemplate restTemplate = ctx.getBean("restTemplate", RestTemplate.class);
// Test retrieve all contacts
System.out.println("Testing retrieve all contacts:");
contacts = restTemplate.getForObject(URL_GET_ALL_CONTACTS, Contacts.class);
listContacts(contacts);
// Test retrieve contact by id
System.out.println("Testing retrieve a contact by id :");
contact = restTemplate.getForObject(URL_GET_CONTACT_BY_ID, Contact.class, 1);
System.out.println(contact);
System.out.println("");
// Test update contact
contact = restTemplate.getForObject(URL_UPDATE_CONTACT, Contact.class, 1);
contact.setFirstName("Kim Fung");
System.out.println("Testing update contact by id :");
restTemplate.put(URL_UPDATE_CONTACT, contact, 1);
System.out.println("Contact update successfully: " + contact);
System.out.println("");
// Testing delete contact
restTemplate.delete(URL_DELETE_CONTACT, 1);
System.out.println("Testing delete contact by id :");
contacts = restTemplate.getForObject(URL_GET_ALL_CONTACTS, Contacts.class);
listContacts(contacts);
// Testing create contact
System.out.println("Testing create contact :");
Contact contactNew = new Contact();
contactNew.setFirstName("JJ");
contactNew.setLastName("Gosling");
contactNew.setBirthDate(new Date());
contactNew = restTemplate.postForObject(URL_CREATE_CONTACT, contactNew, Contact.class);
System.out.println("Contact created successfully: " + contactNew);
}
private static void listContacts(Contacts contacts) {
for (Contact contact: contacts.getContacts()) {
System.out.println(contact);
}
System.out.println("");
}
}
ContactController:
package com.aucklanduni.spring.webservices.restful.controller;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import com.aucklanduni.spring.webservices.domain.Contact;
import com.aucklanduni.spring.webservices.domain.Contacts;
import com.aucklanduni.spring.webservices.service.ContactService;
#Controller
#RequestMapping(value="/contacts")
public class ContactController {
final Logger logger = LoggerFactory.getLogger(ContactController.class);
#Autowired
private ContactService contactService;
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public Contacts listData(WebRequest webRequest) {
return new Contacts(contactService.findAll());
}
#RequestMapping(value="/{id}", method=RequestMethod.GET)
#ResponseBody
public Contact findContactById(#PathVariable Long id) {
return contactService.findById(id);
}
#RequestMapping(value="/", method=RequestMethod.POST)
#ResponseBody
public Contact create(#RequestBody Contact contact, HttpServletResponse response) {
logger.info("Creating contact: " + contact);
contactService.save(contact);
logger.info("Contact created successfully with info: " + contact);
response.setHeader("Location", "/contacts/" + contact.getId());
return contact;
}
#RequestMapping(value="/{id}", method=RequestMethod.PUT)
#ResponseBody
public void update(#RequestBody Contact contact, #PathVariable Long id) {
logger.info("Updating contact: " + contact);
contactService.save(contact);
logger.info("Contact updated successfully with info: " + contact);
//return contact;
}
#RequestMapping(value="/{id}", method=RequestMethod.DELETE)
#ResponseBody
public void delete(#PathVariable Long id) {
logger.info("Deleting contact with id: " + id);
Contact contact = contactService.findById(id);
contactService.delete(contact);
logger.info("Contact deleted successfully");
}
}
ContactDaoImpl:
package com.aucklanduni.spring.webservices.service;
import java.util.List;
import javax.annotation.Resource;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.aucklanduni.spring.webservices.domain.Contact;
#Component
#Repository("contactDao")
#Transactional
public class ContactDaoImpl implements ContactDao {
private Logger _logger = LoggerFactory.getLogger(ContactDaoImpl.class);
private SessionFactory _sessionFactory;
public SessionFactory getSessionFactory() {
return _sessionFactory;
}
#Resource
public void setSessionFactory(SessionFactory sessionFactory) {
this._sessionFactory = sessionFactory;
_logger.debug("SessionFactory class: " + sessionFactory.getClass().getName());
}
#Transactional(readOnly=true)
public List<Contact> findAll() {
List<Contact> result = _sessionFactory.getCurrentSession().createQuery("from Contact c").list();
return result;
}
public List<Contact> findAllWithDetail() {
return _sessionFactory.getCurrentSession().getNamedQuery("Contact.findAllWithDetail").list();
}
public Contact findById(Long id) {
return (Contact) _sessionFactory.getCurrentSession().
getNamedQuery("Contact.findById").setParameter("id", id).uniqueResult();
}
public Contact save(Contact contact) {
_sessionFactory.getCurrentSession().saveOrUpdate(contact);
_logger.info("Contact saved with id: " + contact.getId());
return contact;
}
public void delete(Contact contact) {
_sessionFactory.getCurrentSession().delete(contact);
_logger.info("Contact deleted with id: " + contact.getId());
}
}
ContactServiceImpl (ignore comments as they were used for mock testing purposes):
package com.aucklanduni.spring.webservices.service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.aucklanduni.spring.webservices.domain.Contact;
import com.aucklanduni.spring.webservices.domain.Contacts;
#Component
#Service("contactService")
public class ContactServiceMockImplementation implements ContactService {
//private Contacts _contacts;
#Autowired
private ContactDao contactDao;
// public ContactServiceMockImplementation() {
// Contact contact1 = new Contact();
// contact1.setId(1L);
// contact1.setVersion(1);
// contact1.setFirstName("Clint");
// contact1.setLastName("Eastwood");
// contact1.setBirthDate(new Date());
//
// Contact contact2 = new Contact();
// contact2.setId(1L);
// contact2.setVersion(1);
// contact2.setFirstName("Robert");
// contact2.setLastName("Redford");
// contact2.setBirthDate(new Date());
//
// Contact contact3 = new Contact();
// contact3.setId(1L);
// contact3.setVersion(1);
// contact3.setFirstName("Michael");
// contact3.setLastName("Caine");
// contact3.setBirthDate(new Date());
//
// List<Contact> contactList = new ArrayList<Contact>();
// contactList.add(contact1);
// contactList.add(contact2);
// contactList.add(contact3);
//
// _contacts = new Contacts(contactList);
// }
#Override
public List<Contact> findAll() {
//return _contacts.getContacts();
return contactDao.findAll();
}
// #Override
// public List<Contact> findByFirstName(String firstName) {
// List<Contact> results = new ArrayList<Contact>();
//
// for(Contact contact : _contacts.getContacts()) {
// if(contact.getFirstName().equals(firstName)) {
// results.add(contact);
// }
// }
// return results;
// }
#Override
public Contact findById(Long id) {
// Contact result = null;
//
// for(Contact contact : _contacts.getContacts()) {
// if(contact.getId() == id) {
// result = contact;
// break;
// }
// }
// return result;
return contactDao.findById(id);
}
#Override
public Contact save(Contact contact) {
//return contact;
return contactDao.save(contact);
}
#Override
public void delete(Contact contact) {
// TODO Auto-generated method stub
contactDao.delete(contact);
}
}
Here is my restful-client-app-context.xml which includes the Hibernate config:
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-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/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:schema.sql"/>
<jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="springSessionFactory"/>
</bean>
<!-- <bean id="contactDao" class="com.aucklanduni.spring.webservices.service.ContactDao"></bean> -->
<tx:annotation-driven/>
<context:component-scan base-package="com.aucklanduni.spring.webservices.service" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="springSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.aucklanduni.spring.webservices.domain"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<!-- <constructor-arg ref="httpRequestFactory"/>-->
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="castorMarshaller"/>
<property name="unmarshaller" ref="castorMarshaller"/>
<property name="supportedMediaTypes">
<list>
<bean class="org.springframework.http.MediaType">
<constructor-arg index="0" value="application"/>
<constructor-arg index="1" value="xml"/>
</bean>
</list>
</property>
</bean>
</list>
</property>
</bean>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation" value="classpath:oxm-mapping.xml"/>
</bean>
</beans>
i am importing data from file ,its get the data suceessfully .my flow to call the ruleimplservice from the main class ,where i get the value from file.bt when i call jdbclogdatarepository to save the data ,it shows the following error.the data isreached successfully in impl bt not in jdbc class.
ERRORS
java.lang.NullPointerException
at com.heavymeddlellc.heavymeddle.metrics.service.RuleServiceImpl.insertlogcontent(RuleServiceImpl.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at $Proxy6.insertlogcontent(Unknown Source)
at com.heavymeddlellc.heavymeddle.utils.readingdata.main(readingdata.java:97)
Java code is as below:
package com.heavymeddlellc.heavymeddle.utils;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.test.context.ContextConfiguration;
import com.heavymeddlellc.heavymeddle.metrics.domain.LogData;
import com.heavymeddlellc.heavymeddle.metrics.repository.jdbc.JdbcLogDataRepository;
import com.heavymeddlellc.heavymeddle.metrics.service.RuleService;
import com.heavymeddlellc.heavymeddle.metrics.service.RuleServiceImpl;
#ContextConfiguration(locations = "/hm-metrics-context.xml")
public class readingdata
{
public static void main(String args[])
{
//RuleService ruleService=new RuleService();
List<LogData> dataList = new ArrayList<LogData>();
Resource r= new ClassPathResource("/hm-metrics-context.xml");
BeanFactory factory=new XmlBeanFactory((org.springframework.core.io.Resource) r);
// LogData logData=(LogData) factory.getBean("ruleService");
RuleService ruleService=(RuleService) factory.getBean("ruleService");
// JdbcLogDataRepository dataRepository= (JdbcLogDataRepository) factory.getBean("ruleService");
LogData logData=new LogData();
// public List<LogData> inserttable(LogData logData2)
//{
try
{
BufferedReader reader=new BufferedReader(new FileReader("E://tracker.log"));
String lines;
String[] contentid;
while((lines=reader.readLine())!=null)
{
String[] datas=lines.split(Pattern.quote("|"));
logData.setUserId(datas[0]);
logData.setRequestDate(datas[1]);
System.out.println(datas[1]);
logData.setSessionId(datas[2]);
System.out.println(datas[2]);
// System.out.println(datas[2]);
contentid=datas[2].split("html/meta/content/");
// System.out.println(contentid[0]);
// System.out.println(datas[2]);
logData.setContentId(contentid[0]);
System.out.println(contentid[0]);
logData.setUserAgent(datas[6]);
System.out.println(datas[6]);
logData.setUserType(datas[4]);
logData.setReferer(datas[5]);
logData.setRedirectUrl(datas[7]);
String sessionId=logData.getSessionId();
System.out.println(logData.getSessionId());
String contentId=logData.getContentId();
System.out.println(contentId);
String userAgent=logData.getUserAgent();
System.out.println(userAgent);
String requestDate=logData.getRequestDate();
String userId=logData.getUserId();
String userType=logData.getUserType();
String referer=logData.getReferer();
String redirectUrl=logData.getRedirectUrl();
//Saystem.out.println(datas[4]);
// dataList.add(logData);
// System.out.print(logData.getSessionId());
//ruleService.insertlogcontent(logData.setSessionId(datas[2]),logData.setContentId(contentid[0]), logData.setRequestDate(datas[1]), logData.setUserId(datas[0]),logData.setUserType(datas[4]),logData.setReferer(datas[5]),logData.setRedirectUrl(datas[7]));
ruleService.insertlogcontent(sessionId, contentId, userAgent, requestDate, userId, userType, referer, redirectUrl);
}
}
catch(Exception e)
{
e.printStackTrace();
}
// return dataList;
// }
}}
/**
*
*/
ruleServiceimpls
package com.heavymeddlellc.heavymeddle.metrics.service;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.*;
import org.springframework.transaction.annotation.Transactional;
import com.heavymeddlellc.heavymeddle.metrics.domain.LogData;
import com.heavymeddlellc.heavymeddle.metrics.repository.LogDataRepository;
#Repository
public class RuleServiceImpl implements RuleService {
private static final Logger log = Logger.getLogger(RuleServiceImpl.class);
#Autowired
private LogDataRepository logDataRepository;
#Override
public void insertlogcontent(String sessionId, String contentId, String userAgent,
String requestDate, String userId,
String userType, String referer,
String redirectUrl) {
//logDataRepository.insertlogcontent(sessionId, contentId,userAgent, requestDate, userId, userType, referer, redirectUrl);
System.out.println(sessionId);
System.out.println(requestDate);
System.out.println(userType);
logDataRepository.insertlogcontent(sessionId, contentId, userAgent,
requestDate, userId, userType, referer, redirectUrl);
}
}
/**
*
*/
package com.heavymeddlellc.heavymeddle.metrics.repository.jdbc;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.heavymeddlellc.heavymeddle.metrics.MetricsException;
import com.heavymeddlellc.heavymeddle.metrics.domain.LogData;
import com.heavymeddlellc.heavymeddle.metrics.repository.LogDataRepository;
import com.heavymeddlellc.heavymeddle.utils.readingdata;
#Transactional
#Repository("logDataRepository")
public class JdbcLogDataRepository implements LogDataRepository {
#Autowired
private JdbcTemplate jdbcTemplate;
#Autowired
private final static String LOG_REDIRECT_VIEW_TABLENAME = "hm_log_redirect_view";
private final static String LOG_REDIRECT_URL_LOOKUP_TABLENAME = "hm_log_redirect_url_lookup";
public final static String LOG_ALL_CONTENTS_VIEW_TABLENAME = "hm_log_all_contents_view";
private final static String LOG_ALL_SN_CONTENTS_VIEW = "hm_log_sn_contents_view";
#Override
public void insertlogcontent(String sessionId, String contentId, String userAgent,
String requestDate, String userId,
String userType, String referer,
String redirectUrl) {
int values=0;
System.out.println(userType);
StringBuffer sqlQuery = new StringBuffer(
"insert into "+JdbcLogDataRepository.LOG_ALL_CONTENTS_VIEW_TABLENAME
+"(uri,content_id,content_owner_id,request_date,user_id,user_type,referer,redirect_url) values (?,?,?,?,?,?,?,?)");
values=jdbcTemplate.update(sqlQuery.toString(),sessionId,contentId,userAgent,requestDate,userId,userType,referer,redirectUrl);
}
}
Spring xml
<!-- Activates scanning of #Autowired -->
<context:annotation-config />
<context:component-scan base-package="com.heavymeddlellc.heavymeddle.metrics" />
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (this dependency is defined somewhere else) -->
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="metricsProcessor" class="com.heavymeddlellc.heavymeddle.metrics.processor.MetricsProcessorImpl">
<constructor-arg ref="taskExecutor" />
<property name="ruleService" ref="ruleService"/>
</bean>
<bean id="ruleService" scope="prototype" class="com.heavymeddlellc.heavymeddle.metrics.service.RuleServiceImpl">
<!-- This instructs the container to proxy the current bean-->
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
<!-- <bean id="logDataRepository" scope="prototype" class="com.heavymeddlellc.heavymeddle.metrics.repository.JdbcLogDataRepository">
This instructs the container to proxy the current bean
<aop:scoped-proxy proxy-target-class="false"/>
<property name="ruleService" ref="ruleService"></property>
</bean>
-->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="50" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="150" />
</bean>
</beans>
Replace the following two lines:
Resource r = new ClassPathResource("/hm-metrics-context.xml");
BeanFactory factory = new XmlBeanFactory((org.springframework.core.io.Resource) r);
with this:
ApplicationContext factory = new ClassPathXmlApplicationContext("/hm-metrics-context.xml");
Read this section of the reference documentation about the differences between a BeanFactory and an ApplicationContext.
Your auto-wiring doesn't work because <context:annotation-config/> is processed as a BeanPostProcessor and the BeanFactory is missing this feature of using BeanPostProcessor extension points, as per the link from the docs above.
Here's the error I'm receiving.
Caused by: java.lang.IllegalStateException: Cannot convert value of type [code.ProductFieldSetMapper] to required type [org.springframework.batch.item.file.mapping.FieldSetMapper] for property 'FieldSetMapper': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:264)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:450)
... 23 more
Here's my context file (FileReaderConfig.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:batch="http://www.springframework.org/schema/batch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd">
<bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="file:./output.txt" />
<property name="linesToSkip" value="1" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="PRODUCT_ID,NAME,DESCRIPTION,PRICE" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="code.ProductFieldSetMapper" />
</property>
</bean>
</property>
</bean>
<job id="importProducts" xmlns="http://www.springframework.org/schema/batch">
<step id="readWriteProducts">
<tasklet>
<chunk reader="reader" writer="writer" commit-interval="100" />
</tasklet>
</step>
</job>
Here's the interface (FieldSetMapper.java)
package code;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
public interface FieldSetMapper<T> {
T mapFieldSet(FieldSet fieldSet) throws BindException;
}
Here's ProductFieldSetMapper.java
package code;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
public class ProductFieldSetMapper implements FieldSetMapper<Product> {
public Product mapFieldSet(FieldSet fieldSet) throws BindException {
// TODO Auto-generated method stub
Product product = new Product();
product.setId(fieldSet.readString("PRODUCT_ID"));
product.setName(fieldSet.readString("NAME"));
product.setDescription(fieldSet.readString("DESCRIPTION"));
product.setPrice(fieldSet.readBigDecimal("PRICE"));
return product;
}
}
And here's the class that I'm running (Runner.java)
package code;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.validation.BindException;
public class Runner {
public static void main(String[] args) throws BeansException, BindException {
// TODO Auto-generated method stub
Product product;
ApplicationContext context =
new ClassPathXmlApplicationContext("FileReaderConfig.xml");
ProductFieldSetMapper obj = (ProductFieldSetMapper) context.getBean("FieldSetMapper");
product = (Product) obj.mapFieldSet((FieldSet)context.getBean("lineTokenizer"));
System.out.println(product.getDescription() + ""+product.getId()+""+product.getName());
}
}
I don't see where (or why for that matter)my code is attempting to convert a ProductFieldSetMapper into a FieldSetMapper (which is just an interface, I understand that won't work).
BTW, Product.java is a POJO with variables and their respective setters and getters.
The error was the result of me using my own interface rather than the one provided by Spring. I deleted my interface class and had ProductFieldSetMapper implement org.springframework.batch.item.file.mapping.FieldSetMapper after importing it. That solved the issue.
ProductFieldSetMapper obj =
(ProductFieldSetMapper) context.getBean("FieldSetMapper");
Should be
ProductFieldSetMapper obj =
(ProductFieldSetMapper) context.getBean("fieldSetMapper");
See your bean declaration.
<property name="fieldSetMapper">
<bean class="code.ProductFieldSetMapper" />
</property>
Here is code with some correction:
Runner.java (use DelimitedLineTokenizer class to tokenize a comma separated string into FieldSet that is further used to map it with an object (Product) via ProductFieldSetMapper class)
ApplicationContext context = new ClassPathXmlApplicationContext(
"FileReaderConfig.xml");
ProductFieldSetMapper obj = (ProductFieldSetMapper) context.getBean("fieldSetMapper");
DelimitedLineTokenizer tokenizer = (DelimitedLineTokenizer) context
.getBean("lineTokenizer");
FieldSet fieldSet = tokenizer.tokenize("1,Pepsi,Cold drinks,30");
Product product = (Product) obj.mapFieldSet(fieldSet);
System.out.println(product.getDescription() + "-" + product.getId() + "-"
+ product.getName());
Config xml file: (No need to declare any beans or jobs other than two defined below because you are not using it anywhere in you Main class)
<bean id="lineTokenizer"
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="PRODUCT_ID,NAME,DESCRIPTION,PRICE" />
</bean>
<bean id="fieldSetMapper" class="com.spring.batch.domain.ProductFieldSetMapper" />
ProductFieldSetMapper.java: (There is no need to define your custom FieldSetMapper)
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
public class ProductFieldSetMapper implements org.springframework.batch.item.file.mapping.FieldSetMapper<Product> {
public Product mapFieldSet(FieldSet fieldSet) throws BindException {
Product product = new Product();
product.setId(fieldSet.readString("PRODUCT_ID"));
product.setName(fieldSet.readString("NAME"));
product.setDescription(fieldSet.readString("DESCRIPTION"));
product.setPrice(fieldSet.readBigDecimal("PRICE"));
return product;
}
}
For a detailed sample please read it HERE with extra functionality using spring batch jobs.