Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java EE7 REST server no longer returning List<String> as JSON

The following example works in a Java EE6 (Glassfish3) project of mine but failed after I switched to Java EE7 (Glassfish4). The HTTP request returns "500 Internal Error" without any message in the Glassfish server log. The project was setup using NetBeans8 as Maven Web Project and has no special dependencies, beans.xml or other configuration.

@RequestScoped
@Path("generic")
public class GenericResource {

    @GET
    @Path("ping")
    @Produces(APPLICATION_JSON)
    public List<String> debugPing() {
        return Arrays.asList("pong");
    }

And then:

$ curl -v  http://localhost:8080/mavenproject2/webresources/generic/ping
> GET /mavenproject2/webresources/generic/ping HTTP/1.1
...
< HTTP/1.1 500 Internal Server Error

As as I understand, all REST handling is done by the Jackson reference implementation and that Jackson uses Jersey as underlaying JSON library. One of the two is supposed to have some kind of provider for all basic data types. Only custom made classes need a self written ObjectMapper. Are these concepts still correct?

like image 319
lathspell Avatar asked Oct 01 '22 04:10

lathspell


1 Answers

It took me some hours but I finally solved this question myself. First fact is that the Glassfish4 JAX-RS implementation "Jersey" as switched its underlying JSON library from Jackson 1.x to Eclipselink MOXy. The latter seems not be able to convert Lists, Arrays and arbitrary POJOs to JSON out of the box. Therefore I tried to force JAX-RS to use Jackson 2.x and disable MOXy.

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

// This is Jackson 2.x, Jackson 1.x used org.codehaus.jackson!
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ApplicationPath("rest")
public class RestConfig extends Application {

    private final static Logger log = LoggerFactory.getLogger(RestConfig.class);

    @Override
    public Set<Object> getSingletons() {
        Set<Object> set = new HashSet<>();
        log.info("Enabling custom Jackson JSON provider");
        set.add(new JacksonJsonProvider() /* optionally add .configure(SerializationFeature.INDENT_OUTPUT, true) */);
        return set;
    }

    @Override
    public Map<String, Object> getProperties() {
        Map<String, Object> map = new HashMap<>();
        log.info("Disabling MOXy JSON provider");
        map.put("jersey.config.disableMoxyJson.server", true);
        return map;
    }

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> resources = new java.util.HashSet<>();
        // ... add your own REST enabled classes here ...
        return resources;
    }
}

My pom.xml contains:

    <dependency>
        <!-- REST (Jackson as JSON mapper) -->
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>2.2.3</version>
    </dependency>
    <dependency>
        <!-- REST (Jackson LowerCaseWithUnderscoresStrategy etc.) -->
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.2.3</version>
    </dependency>

Hope this helps someone!

like image 160
lathspell Avatar answered Oct 13 '22 10:10

lathspell