1

I can use String object in JAX-RS rest service but not able to use POJO object. How I should configure a POJO class to enable it to be used as a resource in JAX-RS rest service?

DTO class

public class RestServiceDTO {
    private String groupId;
    public String getGroupId() {
        return groupId;
    }
    public void setGroupId(String groupId) 
        this.groupId = groupId;
    }
    @Override
    public String toString() {
        return "RestServiceDTO [groupId=" + groupId + "]";
    }
}

Rest service:

@Component(
    immediate = true,
    property = {
        JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/greetings",
    },
    service = Application.class
)
public class RestServiceApplication extends Application {
    public Set<Object> getSingletons() {
        return Collections.<Object>singleton(this);
    }
    @POST
    @Path("/post")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public String test(RestServiceDTO dto) {
        String groupid = dto.getGroupId();
        return "{'groupid':'" + groupid + "'}";
    }
}

Error:

2019-02-12 13:33:58.021 ERROR [http-nio-8080-exec-1][JAXRSUtils:83] No message body reader has been found for class com.dto.RestServiceDTO, ContentType: application/json

3 Answers3

2

Since version 7.1 Liferay supports the OSGi JAX-RS Whiteboard specification, which means support for JAX-RS 2.1 using CXF, which also mean that there is support for JAXB annotated POJOs.

If you need to return a simple POJO you would normally be OK just by annotating your POJO class with @XmlRootElement.

Make sure you get JAXB runtime support attached to your application by requiring it on your application component configuration putting the property osgi.jaxrs.extension.select=(osgi.jaxrs.name=jaxb-json) on your application component.

This property will instruct the JAX-RS whiteboard to not start your application until the extension is present and ready for your application.

Since Liferay 7.2 the JAXB default implementation has been changed to Jackson. There is no configuration change needed, but now every POJO can be serialized to JSON even if the POJO is not annotated. Just make sure the jaxb runtime support is attached to your application the same as above.

In both 7.1 and 7.2 you can check the status of your JAX-RS applications, and attached extensions, using the gogo shell command jaxrs:check

csierra
  • 1,010
  • 10
  • 8
0

Liferay uses the Apache CXF implementation of JAX-RS. As @dkb mentioned in the comments you need to provide the annotation that you have in the sample code.

You need to add the dependencies. See the list below and note that some are provided by the platform but some needs to be included in your jar and don't forget the transitive dependencies.

      <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-core</artifactId>
            <version>3.0.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>3.0.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-rs-extension-providers</artifactId>
            <version>3.0.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>2.7.9</version>
        </dependency>

The last thing is. You need to register your Jackson provider within the JAX-RS app. It is done in teh applicaiton class for example like this (there are more ways how to do it).

@Override
public Set<Object> getSingletons() {
    Set<Object> singletons = new HashSet<>();
    singletons.add(getJacksonProvider());
    return Collections.unmodifiableSet(singletons);
}
Miroslav Ligas
  • 1,287
  • 8
  • 22
  • Thanks a lot, @Miroslav Ligas can you please explain in detail how to register Jackson provider within the JAX-RS app? – binal patel Feb 14 '19 at 13:17
0

Add dependency for MAVEN:

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
    <version>2.9.10</version>
</dependency>

for GRADLE:

compileOnly group: 'com.fasterxml.jackson.jaxrs', name: 'jackson-jaxrs-json-provider', version: '2.9.10'

now add this method in your Apllication class

private JacksonJsonProvider getJacksonJsonProvider() {

    JacksonJsonProvider jacksonJsonProvider = new JacksonJsonProvider();

    ObjectMapper objectMapper = new ObjectMapper();

    // Prevent serialization of null and empty string values
    objectMapper.setSerializationInclusion(Include.NON_EMPTY);

    jacksonJsonProvider.setMapper(objectMapper);
    jacksonJsonProvider.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    return jacksonJsonProvider;
}

now change the code of getSingletons() method of your Application class to

@Override
public Set<Object> getSingletons() {

    Set<Object> singletons = new HashSet<>();

    singletons.add(this);

    singletons.add(getJacksonJsonProvider());

    return Collections.unmodifiableSet(singletons);
}

now I think you have to change your return statement to

return Response.ok(JSONFactoryUtil.looseSerializeDeep("{'groupid':'" + groupid + "'}"), MediaType.APPLICATION_JSON).build();

but I am not sure that you have to change your return statement or yours one will run ok