JSON Serialization loop (infinite recursion) in Wildfly - jboss

I am developing a straightforward maven-based JavaEE application in IntelliJ IDEA, and obviously I would like to use Wildfly 8 for both development and production. I simply need to expose some entities through some RESTful web services. Those entities have bidirectional relationships, which leads to a loop when they are going to be serialized into JSON.
Newer versions of Jackson are able to handle this kind of situation with a special annotation. To get that to work, I need to exclude Wildfly's built-in JSON serializer / jackson provider / whatever it is and use the newer version that comes bundled with my application. I have followed the instructions I have found on the web and came up with this jboss-deployment-structure.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<exclusions>
<module name="org.codehaus.jackson.jackson-jaxrs" />
<module name="org.codehaus.jackson.jackson-core-asl" />
<module name="org.codehaus.jackson.jackson-mapper-asl" />
<module name="org.codehaus.jackson.jackson-xc" />
</exclusions>
</deployment>
</jboss-deployment-structure>
The problem is, it doesn't work. Even when I set my pom.xml to something like this:
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>3.0.6.Final</version>
<scope>provided</scope>
</dependency>
</dependencies>
which clearly indicates that nothing should come bundled with my application, I still get this StackOverflowError (caused by the infinite loop) which roots in org.codehaus.jackson package. This is turn means that built-in version of Jackson is still in the works and is not excluded. How can I fix this?
Thanks in advance.
UPDATES
I changed the title because I guess the problem is even bigger. Either I am doing something terribly wrong or there is a serious problem with Wildfly.
I have created a pom.xml with all the jackson 2 libraries (com.fasterxml.jackson*) with a "compile" scope. The libraries are included in the WEB-INF/lib folder. I wrote a #Provider according to Jackson JAX-RS FAQ and I can verify that it is actually read by the JAX-RS implementation (RestEasy), simply because the deployment fails if I do not include jackson libraries in WEB-INF/lib with a ClassNotFoundException. However, I am still getting infinite recursion errors with org.codehaus.X (Jackson 1).
I don't care how, I just need a solution to fix this infinite recursion in Wildfly.

The solution is to create a class which implement MessageBodyWriter<Object> using Jackson's ObjectMapper:
#Provider
#Produces("application/json")
public class JacksonMapper implements MessageBodyWriter<Object> {
#Override
public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return true;
}
#Override
public long getSize(Object object, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return 0;
}
#Override
public void writeTo(Object object, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> stringObjectMultivaluedMap, OutputStream outputStream)
throws IOException, WebApplicationException {
outputStream.write(new ObjectMapper().writeValueAsBytes(object));
}
}
There's no need for any exclusion or Wildfly-specific descriptors.
It doesn't matter if you include the dependencies or not (compile or provided scopes both work fine) as Jackson 2 is included in Wildfly. However, for an unknown reason, it is near to impossible to deactivate Jackson 1.
This solution brings Jackson 2 into the works. Now you can easily avoid serialization loops using the #JsonIdentityInfo annotation. More info here.

Related

java.lang.NoSuchMethodError: org.jboss.logging.Logger.debugf(Ljava/lang/String;I)V Exception while migrating from 12.1.3 to 12.2

I am doing migration from JDev 12.1.3 to 12.2.0. Now there was some problem durnng compilation but it has been resolved by modifiying class path.
Now when I go for deployment then it showing me one exception. That is ...
"java.lang.NoSuchMethodError: org.jboss.logging.Logger.debugf(Ljava/lang/String;I)V"
I am using following dependencies..
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.0.Final</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate.common</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>5.0.1.Final</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
Apart from these dependencies I also looked into "C:\oracle_home12c\wlserver\modules" folder and found there was one "org.jboss.logging.jboss-logging.jar" file.
I replaced the maven repo file from "jboss-logging-3.3.0.Final".
I also looked into "jboss-logging-3.3.0.Final" jar file. There is one Logger class file but it does not contain the debugf(String) method.
Exception type;
Caused by: java.lang.NoSuchMethodError: org.jboss.logging.Logger.debugf(Ljava/lang/String;I)V
at org.hibernate.internal.NamedQueryRepository.checkNamedQueries(NamedQueryRepository.java:149)
at org.hibernate.internal.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:764)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:495)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:802)
at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:135)
at weblogic.persistence.BasePersistenceUnitInfo.initializeEntityManagerFactory(BasePersistenceUnitInfo.java:611)
Can someone help to get rid off this problem?
Thanks in advance
If you are using the glassfish server the the problem might be with the lib provided by glassfish. This error is caused by the use of incompatible version.
Just create a glassfish-web.xml file in the WEB-INF directory. The contents of the file are shown below:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
 <class-loader delegate="false"/>
</glassfish-web-app>
This ensures that glassfish does not load it's internal libraries, but libraries from your project.
I don't know how JDev classloading works, but maybe it takes the a wrong version of jboss-logging which doesn't have the method? Try removing that from the modules dir. And make sure that your app bundles jboss-logging in the .war. It should be brought in by Hibernate's dependencies. If not, add it to the pom.xml.

Java-ee REST server with IntelliJ and Tomcat

I'm trying to implement a REST Server API using Java-ee following this tutorial. Instead of Glassfish, I use Tomcat.
I could develop a servlet
#WebServlet(name = "hello", urlPatterns = "/")
public class HelloWorld extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("=)");
}
}
And join http://localhost:9080/ I can see the smiling face. But when I try to access to the api path (http://localhost:9080/api/recommend/all) I also get the face. If I remove the servlet class, I get a 404 error. I suppose I need something else to build automatically the api but I don't know what.
Could someone tell my what is missing? What should I do?
Update:
In Intellij's Java Enterprise View I see:
Web > HelloWorld
RESTful WS > recommend > all
These are my api classes:
#ApplicationPath("/api")
public class REST_Config extends Application {
}
And the specific method
#Path("recommend")
public class RecommenderController {
#Path("/all")
#GET
#Produces("application/json")
public JsonArray getAll(){
JsonArrayBuilder builder = Json.createArrayBuilder();
builder.add(Json.createObjectBuilder().add("1", "2.5"));
return builder.build();
}
}
And the pom.xml:
<?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>TestREST</groupId>
<artifactId>TestREST</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
</dependencies>
<build>
<finalName>TestREST</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
</plugin>
</plugins>
</build>
</project>
"Instead of Glassfish, I use Tomcat."
Look at this
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
This is nothing more than basically a bunch of interfaces for the EE spec. There is no implementation. Java EE servers will have the implementation. Tomcat is not an EE server. The only part of the EE spec it will definitely implements is the Servlet Specification. You are trying to work with the JAX-RS spec, where Tomcat for sure by default does not have an implementation for. So you need to add that implementation.
The easiest IMO to get started with, is Jersey. You can simple add this dependency
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.17</version>
</dependency>
And it will get you up and running. Keep the Jersey User Guide handy. It will come in use.
Also I don't know what JsonArray is, but what will happen when you run this is you will get some error similar to "No MessageBodyWriter found for JsonArray and media type application/json". You need to provider. If you are going to use the Java EE JSONP API, then you should add the this provider
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-processing</artifactId>
<version>2.17</version>
</dependency>
As you get to working alot with JSON, you wil find this API to be difficult to maintain. I'd recommend using Jackson. If you don't already know it, I'd suggest learning it. It offers simple POJO to JSON mapping. For Jackson, you can add this dependency
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.17</version>
</dependency>

java hibernate 4 org.hibernate.HibernateException: Dialect class not found: org.hibernate.dialect.MYSQLDialect

I'm learning Java EE and Hibernate, and I've run into the following problem:
I've created a Dynamic Web Project in Eclipse, I've converted it into a MAVEN project, added the mysql-connector-java and the hibernate-core dependencies to the pom.xml.
I've added a servlet, and in the doGet method, I've tried to initialize the sessionfactory to create the tables. I'm using tomcat.
When I'm making a request to the servlet I'm getting the following exception:
org.hibernate.HibernateException: Dialect class not found: org.hibernate.dialect.MYSQLDialect
org.hibernate.service.jdbc.dialect.internal.DialectFactoryImpl.constructDialect(DialectFactoryImpl.java:77)
org.hibernate.service.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:65)
org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:146)
org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:76)
org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:160)
org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:132)
org.hibernate.cfg.Configuration.buildTypeRegistrations(Configuration.java:1818)
org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1776)
hu.adamsan.testhibernate.TestHibernate.doGet(TestHibernate.java:74)
pom.xml:
dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.6.Final</version>
</dependency>
</dependencies>
I've tried to look into the Maven Dependencies, org.hibernate.dialect.MySQLDialect.class is in there, in the location: getServletContext().getRealPath(".") ->E:\eclips_jee\workspace.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\TestHibernateWeb\
, in the WEB-INF\lib directory, there is hibernate-core-4.2.6.Final.jar, when I opened it with 7zip, I could find inside the org/hibernate/dialect/MySQL5Dialect.class.
What am I missing? I really have no idea.
doGet method:
PrintWriter w = response.getWriter();
w.println("Testing hibernate<br/>");
w.println(getServletContext().getRealPath(".")+"<br/>");
Configuration config;
ServiceRegistry registry;
SessionFactory factory;
config = new Configuration().addAnnotatedClass(Modell.class);
Properties props = getProperties();
props.setProperty(Environment.HBM2DDL_AUTO, "create");
config.setProperties(props);
registry = new ServiceRegistryBuilder().applySettings(props).buildServiceRegistry();
factory = config.buildSessionFactory(registry);
factory.close();
The answer is in the question. You've found MySQLDialect and MySQL5Dialect in your jar files, but your configuration file tries to use MYSQLDialect. Java is case-sensitive.
I'm puting this because the above answer wasn't accurate for me, In my case I'm using Intellij IDEA While working with Hibernate dependency I was over configuring the pom dependency with a type (pom type) My solution is to remove that type.
<!-- Hibernate JPA dependency -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.3.Final</version>
<type>pom</type>
</dependency>
The working version Is :
<!-- Hibernate JPA dependency -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.3.Final</version>
</dependency>
NO POM TYPE
Which allowed to make ride of the following bug :
java.lang.TypeNotPresentException: Type org.hibernate.SessionFactory not present
that generally was blocking the resolve of the following property
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
and thus while doing the setup of hibernate session factory under the spring framework

Arquillian integration tests and OpenJPA enhancement

I'm working on a set of integration tests using arquillian and dbunit. I can run some of my tests just fine, but not the ones involving entities which have oneToMany relations with data in them. When running my tests I then get a PersistenceException:
Caused by: java.lang.NullPointerException
at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.setInverseRelation(JDBCStoreManager.java:451)
My test looks like this:
#RunWith(Arquillian.class)
#CreateSchema("sql/masterplanCreateTables.sql")
public class MasterPlanManagerBeanDbIT {
#Rule
public PersistenceUnitRule rule = new PersistenceUnitRule();
#Inject
private MasterplanManager instance;
#PersistenceContext
EntityManager entityManager;
#Deployment
public static WebArchive createDeployment() throws Exception {
return ShrinkWrap
.create(WebArchive.class, .....
}
#Test
#UsingDataSet("/data/integration/uttrans/masterplan/validData_dbInput.xml")
public void updateTrip_givenValidInput_expectsTripToBeUpdated() {
Trip input = givenTrips().get(0);
input.setNote("updated value");
Trip updated = instance.updateTrip(input);
checkEquality(input, updated);//checks field by field for equality
}
}
My pom.xml looks like this:
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>1.0.1.Final</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
...
<dependencies>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>arquillian-tomee-embedded</artifactId>
<version>${tomee.version}</version>
<scope>test</scope>
</dependency>
...
</dependencies>
...
I did try the openjpa-maven-plugin to enhance the entities at build-time, but this will afaik alter the compiled entities which later will be deployed to our production environment (using deploy-time enhancement).
With that in mind, is it possible to enable deploy-time enhancement in my arquillian tests?
As I'm using openJpa, I found this link very helpful:
http://openejb.apache.org/javaagent.html
I am simply providing the openejb java-agent to the maven surefire plugin.
If you are using eclipse add -javaagent:{your java agent path} to the VM arguments for the test.
In my case I took the java agent directly from a TomEE installation.

Using Guava bundled with GWT

GWT 2.2 and later includes Guava. The package containing Guava is com.google.gwt.thirdparty.guava. However, there doesn't seem to be a module XML file that would allow this package to be used in client (translatable) code. Based on this observation, it would seem that this copy of Guava is intended for GWT-internal use only.
For GWT projects using Guava, is the suggested approach to download Guava separately? If not, what is the process for including com.google.gwt.thirdparty.guava in client code?
Yes, if you want to use Guava yourself, you'll need the guava and guava-gwt jars, and reference the modules you want in your gwt.xml file. In the past, you've also needed jsr305, although my understanding is that this was being fixed, so you may not need that in r09
Your assumption is correct; it's for internal use only; download it separately. If using Maven, include the following in your pom.xml:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>r07</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>r07</version>
<classifier>gwt</classifier>
<scope>provided</scope>
</dependency>
<!-- for the source/classes for javax.annotation -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>1.3.9</version>
<scope>provided</scope>
</dependency>