Can't Translate XML to JSON with Apache Camel 3.1.0 - java

I'm learning Apache Camel with book Mastering Apache Camel by Jean-Baptiste. I need to learn this framework for use it in my current work.
The version of Apache Camel used in the book is 2.12.4 but I inadvertently made a lot of PoC with the version 3.1.0.
In this moment I'm trying to translate XML files to JSON files but without any result.
My pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.redhat</groupId>
<artifactId>apachecamel-learning</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- Apache CAMEL -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
<!-- MARSHALL AND UNMARSHALL -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jackson</artifactId>
<version>3.1.0</version>
</dependency>
<!-- Camel JMS -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
<version>2.5.0</version>
</dependency>
<!-- ActiveMQ -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.3.2</version>
</dependency>
<!-- OSGi -->
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.3.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
My Java Class:
package com.redhat.pocs.camel.eip;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.model.dataformat.JacksonXMLDataFormat;
public class TestMarshallAndUnmarshall {
public static void main(String[] args) throws Exception {
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() {
from("file:/tmp/in")
.marshal(new JacksonXMLDataFormat())
.to("file:/tmp/out");
}
});
context.start();
Thread.sleep(10000); // Prevent to Camel to shutdown and don't run the route
context.stop();
context.close();
}
}
I tried with XmlJsonDataFormat, JaxbDataFormat, JacksonXMLDataFormat and always with the same error:
Exception in thread "main" org.apache.camel.FailedToCreateRouteException: Failed to create route route1 at: >>> Marshal[org.apache.camel.model.dataformat.JacksonXMLDataFormat#6e4784bc] <<< in route: Route(route1)[From[file:/tmp/in] -> [Marshal[org.apache.came... because of Data format 'jacksonxml' could not be created. Ensure that the data format is valid and the associated Camel component is present on the classpath
Does anyone have any idea what I'm doing wrong?

For Camel 2
Since version 2.10.x there is the camel-xmljson component.
I use it like this (version 2.22.2)
Camel route:
final XmlJsonDataFormat xmlJsonFormat = new XmlJsonDataFormat();
xmlJsonFormat.setRootName("result");
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() {
from("file:/tmp?fileName=in.xml")
.marshal(xmlJsonFormat)
.to("file:/tmp?fileName=out.json")
.end();
}
});
context.start();
Thread.sleep(5000); // Prevent to Camel to shutdown and don't run the route
context.stop();
Pom.xml:
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-xmljson</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>xom</groupId>
<artifactId>xom</artifactId>
<version>1.2.5</version>
</dependency>
...
For Camel 3
The camel-xmljson component is deprecated for this version of camel. I couldn't find a direct way to transform from xml to json.
Unfortunately, the only way I could made this work was using an intermediate pojo. So first I transform from xml to Pojo and then from Pojo to json.
Camel route:
JacksonDataFormat jacksonDataFormat = new JacksonDataFormat();
jacksonDataFormat.setPrettyPrint(true);
jacksonDataFormat.enableFeature(SerializationFeature.WRAP_ROOT_VALUE);
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() {
from("file:/tmp?fileName=in.xml")
.unmarshal().jacksonxml(Order.class)
.marshal(jacksonDataFormat)
.to("file:/tmp?fileName=out.json")
.end();
}
});
context.start();
Thread.sleep(10000); // Prevent to Camel to shutdown and don't run the route
context.stop();
context.close();
Order and Item classes
public class Order {
#JacksonXmlProperty(localName = "name")
private String name;
#JacksonXmlProperty(localName = "items")
private List<Item> items;
public Order() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
public class Item {
#JacksonXmlProperty(localName = "name")
private String name;
public Item() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Order.xml
<order>
<name>123</name>
<items>
<item>
<name>a</name>
</item>
<item>
<name>b</name>
</item>
</items>
</order>
Result Order.json
{
"Order" : {
"name" : "123",
"items" : [ {
"name" : "a"
}, {
"name" : "b"
} ]
}
}
Hope it helps.

xj
(mike drop)
I was looking for same information and almost accidentally found the poorly named "camel-xj". https://camel.apache.org/components/3.18.x/xj-component.html
The XJ component allows you to convert XML and JSON documents directly
forth and back without the need of intermediate java objects. You can even specify an XSLT stylesheet to convert directly to the target JSON / XML (domain) model..

Related

Unable to find message body reader with content type application/json in Jersey Test Framework

I have selected Jersey Test Framework to implement unit test cases for REST services.But i am getting following issue once i ran the test.
Note: I even add the resteasy-jackson-provider into pom file but couldn't help.
Here is the .pom file dependency
<!-- jersey security dependency -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- jersey test framework dependency -->
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-jetty</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>2.3.4.Final</version>
</dependency>
<!--junit Dependency-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
MockServices.Java
#Path("/hello")
public class MockServices {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/world")
public DateVO getHello() {
DateVO j=new DateVO ();
j.setActive(true);
return j;
}
}
MockServicesTest.Java
public class MockServicesTest extends JerseyTest {
#Override
protected Application configure() {
return new ResourceConfig(MockServices.class);
}
#Test
public void test() {
Response hello = target("/hello/world").request().get();
System.out.println(hello.readEntity(String.class));//throw an above exception
}
}
Please let me know how can i overcome this problem.
Override your provider method like this
#Override
protected Application configure() {
ResourceConfig config =new ResourceConfig(MockServices.class).register(JacksonFeature.class).register("Your ContextResolver<ObjectMapper> implementation class");
return config;
}
I had to use explicitly Jersey client implementation to invoke the REST end points.
#Test
public void test() {
final Client client = new JerseyClientBuilder().build();
WebTarget target = client.target("http://localhost:9998");
final Response response =
target.path("/hello/world").request().get();
final String json = response.readEntity(String.class);
}
Reference

Jackson Serializer not invoked Jersey Jax-RS

Developing JAX-RS app and struggle a problem.
Need to customize json-output from my resource so configured Jersey(2.22.2) to use Jackson(2.5) parser instead default Moxy (according to this answer).
Here is pom.xml fragment
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
</dependencies>
<properties>
<jersey.version>2.22.2</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
I also configured web.xml file to use Jackson by default
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
com.mycompany.myresourcepackage
com.fasterxml.jackson.jaxrs
</param-value>
</init-param>
But resource output is deffer from what I configure with annotations and serializer.
Here is model to represent as json
#XmlRootElement(name = "geo")
public class Geometry {
public Geometry() {
coordinates = new ArrayList<List<Double>>();
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#JsonSerialize(using = CoordinatesSerializer.class)
public List<List<Double>> getCoordinates() {
return coordinates;
}
public void setCoordinates( List<List<Double>> coordinates) {
this.coordinates = coordinates;
}
#JsonProperty("tp")
private String type;
private List<List<Double>> coordinates;
}
And serializer
protected CoordinatesSerializer(Class<List<List<Double>>> t) { }
private static final long serialVersionUID = 1L;
#Override
public void serialize(List<List<Double>> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException {
try {
jgen.writeArrayFieldStart("motherfucking-coordinates");
int coordinates_size = value.size();
for (int i = 0; i < coordinates_size; i++) {
jgen.writeStartArray();
jgen.writeNumber(value.get(i).get(0));
jgen.writeNumber(value.get(i).get(1));
jgen.writeEndArray();
}
jgen.writeEndArray();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
And here is resource fragment
#GET
#Path("/route/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Geometry(#PathParam("id") int id) {
// construct and return object
}
Response json is not customized at all.
{"geometry":{"coordinates":["27.56 53.9","27.58 53.88","27.55 53.94"],"type":"LineString"},"id":"1","type":"Feature"}
Desired output is
{"geometry":{"coordinates":[[27.56, 53.9],[27.58, 53.88],[27.55, 53.94]],"type":"LineString"},"id":"1","type":"Feature"}
Thanks a lot.
I finally managed to configure Jersey project to use Jackson JSON parser instead of Moxy(default). The application is running at Glassfish JEE Server.
Maven dependencies
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
Than you need to create class with extends org.glassfish.jersey.server.ResourceConfig. The object of the class is created when app is first loaded.
public class MyApplication extends ResourceConfig {
public MyApplication() {
// create custom ObjectMapper
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// create JsonProvider to provide custom ObjectMapper
JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
provider.setMapper(mapper);
register(provider);
register(JacksonFeature.class);
packages("your.resources.package");
}
}
And created MyApplication class should be registered in web.xml file (to be actually created). Edit section of web.xml.
<servlet>
<servlet-name>App</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>your.app.package.MyApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Listed steps are enough to register Jackson JSON Parser as default for Jersey Jax-RS app.

There was an unexpected error (type=Not Acceptable, status=406) for Spring #RestController, spring-boot

I'm trying to return xml from my #RestController method -
#RestController
public class MCSController {
.
.
#RequestMapping(value = "/encoders", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML })
public List<EncoderVO> getEncoders() {
List<EncoderVO> encoders = null;
try {
encoders = infoService.listEncoders();
} catch (MCSException e) {
logger.error("Error in listing encoders : " + e.getMessage());
}
return encoders;
}
Here is my EncoderVO.java -
#XmlRootElement
public class EncoderVO {
#XmlElement
private Long id;
#XmlElement
private String name;
#XmlElement
private Boolean flagActive;
public EncoderVO() {
}
public EncoderVO(Long id, String name, Boolean flagActive) {
super();
this.id = id;
this.name = name;
this.flagActive = flagActive;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getFlagActive() {
return flagActive;
}
public void setFlagActive(Boolean flagActive) {
this.flagActive = flagActive;
}
}
This is my pom.xml file -
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>mcs</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RELEASE</version>
</parent>
<properties>
<aws.sdk-version>1.9.1</aws.sdk-version>
<liquibase.version>3.3.0</liquibase.version>
</properties>
<!-- Add typical dependencies for a web application -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>jackson-annotations</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
<exclusions>
<exclusion>
<artifactId>jackson-annotations</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- Aws SDK Dependencies -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-elastictranscoder</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sqs</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sns</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-datapipeline</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-cloudfront</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
</dependencies>
</project>
Below is my Application class -
#SpringBootApplication(exclude = { SpringBootWebSecurityConfiguration.class, LiquibaseAutoConfiguration.class })
#ComponentScan(basePackages = { "com.test.ott.mcs" })
#EnableAspectJAutoProxy
#EnableJms
#EntityScan("com.test.ott.mcs.entities")
#EnableJpaRepositories("com.test.ott.mcs.repository")
public class MCSApplication {
#Bean
JmsListenerContainerFactory<?> jmsContainerFactory(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
// A core poll size of 3 threads and a maximum pool size of 10 threads
factory.setConcurrency("3-10");
return factory;
}
// Using factory pattern with spring annotation
#Bean
public FactoryBean serviceLocatorFactoryBean() {
ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
factoryBean.setServiceLocatorInterface(EncodingAPIFactory.class);
return factoryBean;
}
public static void main(String args[]) {
SpringApplication.run(MCSApplication.class, args);
}
}
When I hit the url /encoders in browser, i get the below error -
There was an unexpected error (type=Not Acceptable, status=406). Could
not find acceptable representation
The jackson related jars in my calsspath are -
jackson-core-asl : 1.9.13
jackson-jaxrs : 1.9.13
jackson-mapper-asl : 1.9.13
jackson-annotations : 2.6.3
jackson-core : 2.6.3
jackson-module-jaxb-annotations : 2.2.3
jackson-jaxrs-json-provider : 2.2.3
jackson-jaxrs-base : 2.5.4
jackson-databind : 2.6.3
So, I have MappingJackson2HttpMessageConverter in my classpath.
Please suggest. Thanks in advance.
There is a solution that will work out-of-the-box, similarly to JAX-RS but with a bit worse output. The solution uses jackson-dataformat-xml. Add dependency to your project:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
Response will look like this:
<?xml version="1.0" encoding="UTF-8"?>
<List>
<item>
<id>1</id>
<name>testEncoder1</name>
<flagActive>true</flagActive>
</item>
<item>
<id>2</id>
<name>testEncoder2</name>
<flagActive>true</flagActive>
</item>
<item>
<id>3</id>
<name>testEncoder3</name>
<flagActive>true</flagActive>
</item>
</List>
For further details please look at Spring MVC Way (jackson-dataformat-xml)
try
http://localhost:8080/mcs-0.0.1-SNAPSHOT/encoders.
mcs is the name of the application and
0.0.1-SNAPSHOT the version.
If it doesn't works you have to add a global path into the RequestController. Something like:
#RestController
#RequestMapping(value = "/mcs")
public class MCSController {
.
.
#RequestMapping(value = "/encoders", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML })
public List<EncoderVO> getEncoders() {
and this request:
http://localhost:8080/mcs-0.0.1-SNAPSHOT/mcs/encoders
i hope it helps you.
Cheers
Add this dependecy in you POM.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
problem is with version of this jar. so please try out this solution

neo4j in JEE (JBoss) environment:

I have built a RESTful web service for Wildfly using Neo4j OGM, but when I access it I get a NullPointerException.
It seems that a Map that should be populated with my model classes has not been initialized by the time it is accessed. Why is this happening?
Upfront I have to say that this module, salessupport-ui, is currently implemented as a fat client using javafx and it works fine connecting to the neo4j community edition 2.2.4, reading, writing, no problem.
What I would like to do now and this is where I face problems, I want to use wildfly as a server which itself connects to neo4j, thus that the javafx client application sends requests only to the wildfly server.
The protocol which I decided to use is REST, the implementation which is already kind-of provided on wildfly is resteasy.
Below are 1) the exception and some debugging info, 2) details about my context, project structure and the code for my classes.
1. Problem
Here are the exception and my findings when debugging.
Exception
Now when I call this REST service by entering http://localhost:8080/salessupport-restsvc/rest/address/list in the browser, the following exception is raised:
00:07:38,458 ERROR [io.undertow.request] (default task-5) UT005023: Exception handling request to /salessupport-restsvc/rest/address/list: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:76)
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:212)
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:149)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:372)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:80)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:172)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:774)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at org.neo4j.ogm.metadata.MetaData.entityType(MetaData.java:231)
at org.neo4j.ogm.session.Neo4jSession.entityType(Neo4jSession.java:451)
at org.neo4j.ogm.session.delegates.LoadByTypeDelegate.loadAll(LoadByTypeDelegate.java:55)
at org.neo4j.ogm.session.delegates.LoadByTypeDelegate.loadAll(LoadByTypeDelegate.java:94)
at org.neo4j.ogm.session.Neo4jSession.loadAll(Neo4jSession.java:114)
at groupid.salessupport.db.core.ApplicationContext$GraphRepositoryImpl.findAll(ApplicationContext.java:74)
at groupid.salessupport.restsvc.impl.SimpleRestGraphRepositoryImpl.findAll(SimpleRestGraphRepositoryImpl.java:29)
at groupid.salessupport.restsvc.impl.AddressRestImpl$Proxy$_$$_WeldClientProxy.findAll(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:137)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:296)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:250)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:237)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356)
... 32 more
Debugging info
By debugging I can see that it goes, as expected, to my first breakpoint in class SimpleRestGraphRepositoryImpl, method findAll() calling repository.findAll();
2nd also expected, it goes to the inner GraphRepositoryImpl class to method findAll(...) and line context.getSession().loadAll(clazz); which creates a Session.
A few steps later it tries in org.neo4j.ogm.metadata.MetaData class in method _classInfo(String,String,String) to call domainInfo.getClassInfosWithAnnotation(nodeEntityAnnotation); where nodeEntityAnnotation="org.neo4j.ogm.annotation.NodeEntity".
In the DomainInfo class method getClassInfosWithAnnotation which is then invoked the map annotationNameToClassInfo is empty. I expect it to be filled with my models, which obviously happens in the javafx environment, but not in the JavaEE env.
here is that method
public List<ClassInfo> getClassInfosWithAnnotation(String annotation) {
return annotationNameToClassInfo.get(annotation);
}
For checking, if the REST mechanism works as is I put a class next to the AddressRestImpl>
#Path("dummy")
public class DummyImpl {
#GET
#Path("list")
#Produces(MediaType.APPLICATION_JSON)
public List<Amount> getAll() {
return Arrays.asList(new Amount());
}
}
Calling this in the browser by navigating to http://localhost:8080/salessupport-restsvc/rest/dummy/list results in the expected: [{"amount":null,"currency":null}]
I have plenty of simple stuff to improve here, I have tried quite a lot of approaches, also on Tomcat 8 the same exception happens, but there the Rest approach did not work even in the dummy case so I switched to wildfly.
Did I find a bug here or is there something simply I have missed in my setup?
2) Project and Code Details
Here is information about my environment, project structure and the code I run when I have this problem.
Environment
My environment is as follows:
I have Neo4J community edition 2.2.4.
I downloaded wildfly-9.0.1.Final and, except for a management port which conflicted with my NVidia Driver Software I left everything untouched.
Project Structure
I have a maven multimodule application which consists of the following modules:
<modules>
<module>salessupport-ui</module>
<module>salessupport-intf</module>
<module>salessupport-db</module>
<module>salessupport-restsvc</module>
</modules>
The dependencies are as follows:
salessupport-intf <-- salessupport-db
^
|-- salessupport-ui
|-- salessupport-restsvc
Dependencies
Let me explain the dependencies:
salessupport parent has a dependency management definition like this:
<dependencyManagement>
<dependencies>
...
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm</artifactId>
<version>1.1.2</version>
<exclusions>
<exclusion>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
salessupport-intf uses the following dependencies:
<dependencies>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>
salessupport-restsvc pom.xml is
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>groupid</groupId>
<artifactId>salessupport</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>salessupport-restsvc</artifactId>
<name>salessupport-restsvc</name>
<url>http://maven.apache.org</url>
<properties>
<jersey.version>1.19</jersey.version>
<resteasy.version>3.0.11.Final</resteasy.version>
</properties>
<dependencies>
<dependency>
<groupId>groupid</groupId>
<artifactId>salessupport-intf</artifactId>
</dependency>
<dependency>
<groupId>groupid</groupId>
<artifactId>salessupport-db</artifactId>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>jaxrs-api</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
<version>${resteasy.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<packaging>war</packaging>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>${version.war.plugin}</version>
<configuration>
<!-- webXml>src\main\webapp\WEB-INF\web.xml</webXml -->
<failOnMissingWebXml>false</failOnMissingWebXml>
<packagingExcludes>
org.neo4j.server.rest.discovery,
org.neo4j.server.rest.web
</packagingExcludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Code
Here are the relevant classes.
GraphRepository interface
I defined my custom GraphRepository interface:
public interface GraphRepository<S> {
Iterable<S> findAll(Iterable<Long> nodeIds);
Iterable<S> findAll();
void delete(S arg0);
S save(S arg0);
}
Model Classes
There are some model classes, e.g.:
package groupid.salessupport.db.model;
import java.text.DecimalFormat;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.NodeEntity;
#NodeEntity(label="Amount")
public class Amount {
#GraphId Long id;
private Double amount;
private Currency currency;
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
#Override
public String toString() {
return new DecimalFormat().format(amount)+" "+currency;
}
}
and
#NodeEntity(label="Currency")
public class Currency extends BaseObject {
#Override
public String toString() {
return getName();
}
}
Generic Simple Rest Graph Repository interface
public interface ISimpleRestGraphRepository<T> {
#DELETE
#Path("delete")
#Consumes(MediaType.APPLICATION_JSON)
public void delete(T arg0);
#PUT
#Path("save")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public T save(T arg0);
#GET
#Path("list")
#Produces(MediaType.APPLICATION_JSON)
public Iterable<T> findAll();
#POST
#Path("listbyids")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Iterable<T> findAll(Iterable<Long> arg0);
}
REST Interface Definition for Amount
#Path("amount")
public interface AmountRest extends ISimpleRestGraphRepository<Amount> {
}
REST Activator
#ApplicationPath("/rest")
public class JaxRsActivator extends Application {
}
Generic implementation of my REST Service
#RequestScoped
public class SimpleRestGraphRepositoryImpl<T> implements ISimpleRestGraphRepository<T> {
private final GraphRepository<T> repository;
public SimpleRestGraphRepositoryImpl(GraphRepository<T> repository) {
this.repository = repository;
}
#Override
public void delete(T arg0) {
repository.delete(arg0);
}
#Override
public T save(T arg0) {
return repository.save(arg0);
}
#Override
public Iterable<T> findAll() {
return repository.findAll();
}
#Override
public Iterable<T> findAll(Iterable<Long> arg0) {
return repository.findAll(arg0);
}
}
... and the specific Implementation for Address:
public class AmountRestImpl extends SimpleRestGraphRepositoryImpl<Amount> implements AmountRest {
public AmountRestImpl() {
super(NeoRepositories.getInstance().getAmountRepository());
}
}
DB Connection
in salessupport-db we connect to the database with some code:
public class ApplicationContext {
private SessionFactory sessionFactory;
private Session openSession;
public ApplicationContext() {
}
public SessionFactory getSessionFactory() {
if (sessionFactory == null) {
sessionFactory = new SessionFactory("groupid.salessupport.db.model");
}
return sessionFactory;
}
public Session getSession() {
if (openSession == null) {
openSession = getSessionFactory().openSession("http://localhost:7474",
"username", "password"); // it is not really like this
}
return openSession;
}
public <S,G extends GraphRepository<S>> GraphRepository<S> getGraphRepository(Class<S> clazz) {
return new GraphRepositoryImpl<S>(this, clazz);
}
public static class GraphRepositoryImpl<S> implements GraphRepository<S> {
private ApplicationContext context;
private Class<S> clazz;
public GraphRepositoryImpl(ApplicationContext context, Class<S> clazz) {
this.context = context;
this.clazz = clazz;
}
#Override
public Iterable<S> findAll(Iterable<Long> nodeIds) {
List<Long> listNodeIds;
if (nodeIds instanceof List) {
listNodeIds = (List<Long>) nodeIds;
} else {
listNodeIds = new LinkedList<>();
for (Long l : nodeIds) {
listNodeIds.add(l);
}
}
return context.getSession().loadAll(clazz,listNodeIds);
}
#Override
public Iterable<S> findAll() {
return context.getSession().loadAll(clazz);
}
#Override
public void delete(S arg0) {
Session session = context.getSession();
Transaction transaction = session.beginTransaction();
context.getSession().delete(arg0);
transaction.commit();
transaction.close();
}
#Override
public S save(S arg0) {
Session session = context.getSession();
Transaction transaction = session.beginTransaction();
session.save(arg0);
transaction.commit();
transaction.close();
return arg0;
}
}
}
Usage
Implementors acquire an instance of this GraphRepository quick and dirty with a "singleton":
public class NeoRepositories {
private ApplicationContext context;
private static final NeoRepositories INSTANCE = new NeoRepositories();
private NeoRepositories() {
context = new ApplicationContext();
}
public GraphRepository<Person> getPersonRepository() {
return context.getGraphRepository(Person.class);
}
public static NeoRepositories getInstance() {
return INSTANCE;
}
public GraphRepository<Amount> getAmountRepository() {
return context.getGraphRepository(Amount.class);
}
...
}
P.S.: It is my first question on stackoverflow, I hope I wrote as little and as much as necessary to convey the problem ...
Is this #NodeEntity from Spring Data Neo4j? If yes, Spring must be setup correctly, which I cannot find here.
In https://github.com/neo4j/neo4j-ogm/issues/48 there has been an update, which has been implemented with neo4j-ogm version >2 .
I made the whole sourcecode available on https://github.com/mkirchmann/hello-neo4j-ogm , No guarantee that everything is working or all is correct, at least listing the whole nodes for one type should be possible. And don't forget to set up ogm.properties correctly.
The key for the solution is the vfs driver for neo4j-ogm, which can be found in https://github.com/mkirchmann/neo4j-ogm-resourceresolver-vfs (it has been forked from ctpconsulting, use version 2.1.1 and mvn install in order to make it available in your local maven repository)
pom.xml
The following pom.xml is setting up the necessary (maybe more, not sure), so that a Rest call can be made successfully.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.neuenberger</groupId>
<artifactId>hello-neo4j-ogm</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HelloNeo4jOgmOnWildFly</name>
<description>Very Simple configuration to use neo4j ogm on WildFly application server</description>
<packaging>war</packaging>
<properties>
<neo4jogmversion>2.1.1</neo4jogmversion>
<resteasy.version>3.1.1.Final</resteasy.version>
<version.war.plugin>3.0.0</version.war.plugin>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
<version>${resteasy.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.ctp.neo4j</groupId>
<artifactId>neo4j-ogm-resourceresolver-vfs</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>${neo4jogmversion}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-http-driver</artifactId>
<version>${neo4jogmversion}</version>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>${version.war.plugin}</version>
<configuration>
<!-- webXml>src\main\webapp\WEB-INF\web.xml</webXml -->
<failOnMissingWebXml>false</failOnMissingWebXml>
<packagingExcludes>
org.neo4j.server.rest.discovery,
org.neo4j.server.rest.web
</packagingExcludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>neo4j</id>
<name>Neo4j</name>
<url>http://m2.neo4j.org/</url>
</repository>
</repositories>
</project>
Thanks for everyones contribution and support!

restlet syntax for jersey version 1 request list of objects

I am trying to convert the following jersey code to restlet.
WebResource webResource = client.resource("/getlistofobjects");
List<MyObject> thisMemberObjects = webResource
.accept("application/json")
.get(new GenericType<List<MyObject>>(){});
thisListOfObjects.addAll((List<MyObject>)thisMemberObjects);
First you need to create an annotated interface, as described below:
public interface MyService {
#Get
List<MyObject> getObjs();
}
Then you can leverage Restlet converter from class ClientResource based on this interface with code like this:
ClientResource cr = new ClientResource("http://.../getlistofobjects");
cr.accept(MediaType.APPLICATION_JSON);
MyService myService = cr.wrap(MyService.class);
List<MyObject> objs = myService.getObjs();
Don't forget to add in your classpath the extension org.restlet.ext.jackson that will automatically convert the JSON content to Java objects.
Here a sample pom.xml file:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.restlet</groupId>
<artifactId>test.restlet.client</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<version>1.0.0-snapshot</version>
<properties>
<java-version>1.7</java-version>
<restlet-version>2.3.1</restlet-version>
</properties>
<dependencies>
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet</artifactId>
<version>${restlet-version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet.ext.jackson</artifactId>
<version>${restlet-version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet.ext.httpclient</artifactId>
<version>${restlet-version}</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven-restlet</id>
<name>Public online Restlet repository</name>
<url>http://maven.restlet.com</url>
</repository>
</repositories>
</project>
Edited
For the following response payload:
{
"elitFileBasic": [
{
"application":"$TRACKING",
"fileName":"FILE.TRACKING.DATA"
},
{
"application":"$TRACKING$",
"fileName":"TRACKING.EVENT.5"
}
]
}
You need to have the following bean:
public class ResponseBean {
private List<ResponseElementBean> elitFileBasic;
public List<ResponseElementBean> getElitFileBasic() {
return this.elitFileBasic;
}
public void setElitFileBasic(List<ResponseElementBean> elitFileBasic) {
this.elitFileBasic = elitFileBasic;
}
}
public class ResponseElementBean {
private String application;
private fileName;
// Getters and setters
(...)
}
In this case, the annotated interface would be:
public interface MyService {
#Get
ResponseBean getObjs();
}
You can notice that you can update response deserialization with Jackson to support a list of objects as return of the method getObjs. For such use case, you need to register a custom deserializer. This answer can give you some interesting hints: Restlet Complex Object to XML serializaton.
Hope it helps you,
Thierry

Categories

Resources