0
votes

Creating an restful application but it is not returning the response in XML. Even there is no log on the console when hitting the URL "http://localhost:8080/message/webapi/messages".

I am returning a list and using @Produces(MediaType.APPLICATION_XML) to return the response in XML.

MessageResource.java

package org.porwal.restful.message.resources;

import java.util.List;

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

import org.porwal.restful.message.model.Message;
import org.porwal.restful.message.service.MessageService;

@Path("/messages")
public class MessageResource {

    MessageService ms = new MessageService();

    @GET
    @Produces(MediaType.APPLICATION_XML)
    public List<Message> getMessage(){
        return ms.getAllMessage();
    }

}

Message.java

package org.porwal.restful.message.model;

import java.util.Date;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement( name = "Message" )
public class Message {

    public long id;
    public String message;
    public Date created;
    public String author;

    public Message() {

    }

    public Message(long id, String message, String author) {
        this.id = id;
        this.message = message;
        this.author = author;
        this.created = new Date();
    }

    public long getId() {
        return id;
    }
    @XmlElement (name = "ID")
    public void setId(long id) {
        this.id = id;
    }
    public String getMessage() {
        return message;
    }
    @XmlElement (name = "Message")
    public void setMessage(String message) {
        this.message = message;
    }
    public Date getCreated() {
        return created;
    }
    @XmlElement (name = "Created")
    public void setCreated(Date created) {
        this.created = created;
    }
    public String getAuthor() {
        return author;
    }
    @XmlElement (name = "Author")
    public void setAuthor(String author) {
        this.author = author;
    }

}

This is working if i do not use @XMLRootElement annotation and TEXT_PLAIN is returned well through the URL. I also tried to remove @XmlElement for each fields but no luck. When i remove @XMLRootElement then MessageBodyWriter error can be seen in logs on eclipse console but when includes @XMLRootElement then no logs on eclipse console and URL "http://localhost:8080/message/webapi/messages" throws the error:

Error in case of @XmlRootElement is missing.

org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo SEVERE: MessageBodyWriter not found for media type=application/xml, type=class java.util.ArrayList, genericType=java.util.List<org.porwal.restful.message.model.Message>. This exception comes only when i commented the line "//@XmlRootElement( name = "Message" )".

HTTP Status 500 – Internal Server Error

Can someone please tell what i am missing here?

1
Try to register this DebugExceptionMapper with your app. See if you can get a stack trace. There is an exception but it is being swallowed by Jersey. Using this, it should print the error, which should give you an idea of what the problem is. Also, please post the error here when you get it. Just edit your post and add it at the bottom.Paul Samsotha
If you are already seeing a stack trace (the MessageBodyWriter error), please post it here.Paul Samsotha
Thank you very much for instructions. It is quite helpful to register the class DebugExceptionMapper. :)Nitin Porwal

1 Answers

1
votes

You need to make all your fields in the Message class private. If you leave them as public, then JAXB will treat it as a property, and will consider it duplicate properties as you also haves JavaBean properties (getters/setters).

@XmlRootElement( name = "Message" )
public class Message {

    private long id;
    private String message;
    private Date created;
    private String author;

    // ...
}

How I figured this out was by using a generic ExceptionMapper

@Provider
public class DebugExceptionMapper implements ExceptionMapper<Exception> {

    @Override
    public Response toResponse(Exception exception) {
        exception.printStackTrace();
        return Response.serverError().entity(exception.getMessage()).build();
    } 
}

You can register this with your application and it will catch unmapped exceptions and you can do whatever you want with it. Here we just print the stack trace. If we don't handle it, it will just get swallowed up and we will never know what happened.

When running the app with the ExceptionMapper, here's the error message I got.

Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 4 counts of IllegalAnnotationExceptions
Class has two properties of the same name "author"
    this problem is related to the following location:
        at public java.lang.String com.example.Message.getAuthor()
        at com.example.Message
    this problem is related to the following location:
        at public java.lang.String com.example.Message.author
        at com.example.Message
Class has two properties of the same name "created"
    this problem is related to the following location:
        at public java.util.Date com.example.Message.getCreated()
        at com.example.Message
    this problem is related to the following location:
        at public java.util.Date com.example.Message.created
        at com.example.Message
Class has two properties of the same name "id"
    this problem is related to the following location:
        at public long com.example.Message.getId()
        at com.example.Message
    this problem is related to the following location:
        at public long com.example.Message.id
        at com.example.Message
Class has two properties of the same name "message"
    this problem is related to the following location:
        at public java.lang.String com.example.Message.getMessage()
        at com.example.Message
    this problem is related to the following location:
        at public java.lang.String com.example.Message.message
        at com.example.Message

You can clearly see what the problem is. And aside from avoiding this error, this is how encapsulation is supposed to work anyway; the fields should be private and exposed via getters and setters.