Accueil > Apache CXF, Mongo JEE, MongoDB > Mongo JEE [step6]

Mongo JEE [step6]


In [step5] we have modified our JAX-RS LogsService to returns List of Pojo by using :

With Pojo Mapper MongoJack, the LogsService looks like this:

@GET
@Path("/all")
@Produces(MediaType.APPLICATION_JSON)
public List<Log> findAll() {
	DB db = MongoHolder.connect().getDB("websites");
	DBCollection dbColl = db.getCollection("logs");
	JacksonDBCollection<Log, String> coll = JacksonDBCollection.wrap(
          dbColl, Log.class, String.class);
	return coll.find().toArray();
}

When I have studied how to use Mongo in JEE Application with JAX-RS, I have read the great article Modern Web Apps using JAX-RS, MongoDB, JSON, and jQuery. After reading this article, I told me « why we need to use a Pojo Mapper with JAX-RS although Mongo manages their data with BSON representation? », on other words why we could not develop our JAX-RS service like this :

@GET
@Path("/all")
@Produces(MediaType.APPLICATION_JSON)
public DBCursor findAll() {
	DB db = MongoHolder.connect().getDB("websites");
	DBCollection coll = db.getCollection("logs");
	return coll.find();
}

Using DBCursor avoids to create a Pojo and avoids to serialize the Pojo to JSON. So I have decided to create Mongo JEE project. In this article we will modify our JAX-RS LogsService to use Mongo DBCursor in the service by using the JAX-RS provider of the Mongo JEE.

Download

You can download step6.zip which hosts the Eclipse Project which contains the explained sources in this article. To use it, unzip it and import this project in your Eclipse workspace. As soon as you will do that, your workspace will look like this :

This Eclipse project contains:

  • LogService is JAX-RS service which returns Mongo DBCursor.
  • MyJaxrsApplication is JAX-RS application which register the JAX-RS LogsService and Mongo JEE JAX-RS providers.
  • web.xml declares the Apache CXF JAX-RS implementation and set MyJaxrsApplication as JAX-RS Application

Download JARs with maven

This project contains the same dependencies than step4 (no need to use MongoJack and Apache CXF JSONProvider).

LogsService – DBCursor

Modify org.samples.mongodb.services.LogsService like this:

package org.samples.mongodb.services;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.jee.MongoHolder;

@Path("/logs")
public class LogsService {

	@GET
	@Path("/all")
	@Produces(MediaType.APPLICATION_JSON)
	public DBCursor findAll() {
		DB db = MongoHolder.connect().getDB("websites");
		DBCollection coll = db.getCollection("logs");
		return coll.find();
	}

}

Without Mongo JEE

In this step we will not use Mongo JEE to manage DBCursor with JAX-RS. We will see the problem without JAX-RS provider and we will fix it by developping our own JAX-RS provider.

MyJaxrsApplication – with problems

At this step we will use the MyJaxrsApplication of the previous article [step5] :

package org.samples.mongodb.jaxrs;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.core.Application;

import org.samples.mongodb.services.LogsService;

public class MyJaxrsApplication extends Application {

	private final Set<Object> singletons;

	public MyJaxrsApplication() {
		singletons = new HashSet<Object>();
		addSingleton(new LogsService());
	}

	protected void addSingleton(Object singleton) {
		singletons.add(singleton);
	}

	@Override
	public Set<Object> getSingletons() {
		return singletons;
	}
}

Test LogsService – with problem

  • run the StartServer class to start the server.
  • access with your webbrowser to the URL http://localhost:8081/mongo/jaxrs/logs/all/ and you will see the following error :
    No message body writer has been found for response class DBCursor.

This error occurs because Apache CXF doesn’t find JAX-RS provider to serialize the DBCursor to JSON. Mongo JEE provides those JAX-RS provider but before using it, it can be interesting to develop it (with simply mean).

MyDBCursorProvider

To fix the previous problem, create JAX-RS provider org.samples.mongodb.jaxrs.MyDBCursorProvider to serialize DBCursor to JSON like this:

package org.samples.mongodb.jaxrs;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

import com.mongodb.DBCursor;
import com.mongodb.jee.util.JSON;

@Provider
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class MyDBCursorProvider implements MessageBodyWriter<DBCursor> {

	@Override
	public boolean isWriteable(Class<?> atype, Type genericType,
			Annotation[] annotations, MediaType mediaType) {
		if (DBCursor.class.isAssignableFrom(atype)) {
			// the given class type is DBCursor
			return true;
		}
		return false;
	}

	public void writeTo(DBCursor cursor, Class<?> type, Type genericType,
			Annotation[] annotations, MediaType mediaType,
			MultivaluedMap<String, Object> httpHeaders,
			OutputStream entityStream) throws IOException,
			WebApplicationException {

		// Write the DBCursor as JSON array stream.
		JSON.serialize(cursor, entityStream);
	}

	@Override
	public long getSize(DBCursor t, Class<?> type, Type genericType,
			Annotation[] annotations, MediaType mediaType) {
		// Return -1 if the content length cannot be determined
		return -1;
	}

}

To use our JAX-RS provider, we need to register it in the JAX-RS Application. To do that modify org.samples.mongodb.jaxrs.MyJaxrsApplication like this:

package org.samples.mongodb.jaxrs;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.core.Application;

import org.samples.mongodb.services.LogsService;

public class MyJaxrsApplication extends Application {

	private final Set<Class<?>> classes;
	private final Set<Object> singletons;

	public MyJaxrsApplication() {
		classes = new HashSet<Class<?>>();
		addClass(MyDBCursorProvider.class);
		 
		singletons = new HashSet<Object>();
		addSingleton(new LogsService());
	}

	@Override
	public Set<Class<?>> getClasses() {
		return classes;
	}

	protected void addClass(Class<?> clazz) {
		classes.add(clazz);
	}

	protected void addSingleton(Object singleton) {
		singletons.add(singleton);
	}

	@Override
	public Set<Object> getSingletons() {
		return singletons;
	}
}

Test LogsService – MyDBCursorProvider

Now we can test our JAX-RS provider :

  • run the StartServer class to start the server.
  • access with your webbrowser to the URL http://localhost:8081/mongo/jaxrs/logs/all/ to see the JSON array of logs and see the « application/json » of the content type :

You can check that the JSON array is the same than the Mongo JSON array like (see [step4]).

With Mongo JEE

Mongo JEE provides several JAX-RS providers for Mongo and provides too a JAX-RS Application JaxrsMongoApplication which registers Mongo JAX-RS providers.

MyJaxrsApplication – JaxrsMongoApplication

Modify MyJaxrsApplication to extend JaxrsMongoApplication like this:

package org.samples.mongodb.jaxrs;

import org.samples.mongodb.services.LogsService;

import com.mongodb.jee.jaxrs.JaxrsMongoApplication;

public class MyJaxrsApplication extends JaxrsMongoApplication {

	public MyJaxrsApplication() {
		super.addSingleton(new LogsService());
	}

}

Run the StartServer class to start the server and check that service works again.

Remove _id

The returned JSON stream to the browser, contains the « _id » key. But it’s possible to remove « _id » property .

Modify LogsService like this:

package org.samples.mongodb.services;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.jee.MongoHolder;

@Path("/logs")
public class LogsService {

	@GET
	@Path("/all")
	@Produces(MediaType.APPLICATION_JSON)
	public DBCursor findAll() {
		DB db = MongoHolder.connect().getDB("websites");
		DBCollection coll = db.getCollection("logs");
		BasicDBObject fieldsToIgnore = new BasicDBObject("_id", false);
		return coll.find(null, fieldsToIgnore);
	}

}

Restart the server and test it to check that every thing is working again.

Conclusion

In this article we have seen how to manage Mongo structure with JAX-RS service by using Mongo JEE.

In the next article [step7] we will add a new method service to return paginated logs list.

Catégories :Apache CXF, Mongo JEE, MongoDB
  1. Aucun commentaire pour l’instant.
  1. Mai 15, 2013 à 9:43

Laisser un commentaire