0
votes

I am using Jersey version 2.29 /java 1.8 on tomcat version 8.5 and trying to retrurn the hasmap<String,String> from jersey rest post service call.

I am getting below exception on server when it is trying to write the hasmap in response.

Aug 23, 2019 10:20:47 PM org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo SEVERE: MessageBodyWriter not found for media type=application/xml, type=class java.util.LinkedHashMap, genericType=java.util.Map.

Below are the details of pom.xml,server and jersey client side code.

pom.xml

<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
</dependency>
 <dependency> 
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId> 
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId> 
    <artifactId>jaxb-impl</artifactId> 
    <version>2.3.1</version> 
</dependency> 
<dependency> 
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId> 
    <version>2.3.1</version> </dependency> 
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>${jersey.version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-jaxb</artifactId>
    <version>${jersey.version}</version>
</dependency>

Client Code

ClientConfig configuration=new ClientConfig();
Client restClientConfig = ClientBuilder.newClient(configuration);
WebTarget webTarget=restClientConfig.target("http://localhost:8080/messenger/webapi/messages/testMap");
HashMap<String,String> mapStr=new HashMap<String,String>();     
mapStr.put("a","1");
mapStr.put("b","2");
webTarget.request()
.accept(MediaType.APPLICATION_XML)
.post(Entity.json(mapStr));

Map<String,String> responseMap = new HashMap<String,String>();
GenericType<Map<String,String>> entity = new GenericType<Map<String,String>>() {};
Response xmlResponse = Response.ok(entity).build();
System.out.println("XMLResponse Is :" + xmlResponse + ":"+ responseMap.size());

Jersey Post Service code

@POST
@Path("/testMap")
@Produces(value = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Consumes(value = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Map<String,String>  postMapMessage(Map<String,String> mapMessage) {
    System.out.println("It is been invoked....and this time we will add the new MapMessage");
    if(mapMessage!=null)
    {
        System.out.println("Size of the Map Message:" + mapMessage.size());
        mapMessage.put("c","3");
    }
    return mapMessage;
}

I have tried several solutions found on internet but nothing seems to be working for this.

Can anybody please tell me what wrong I am doing in above code snippet?

1
Maps don't map well to XML. Unlike JSON, XML needs a root element and is more suitable for a tree structure. Maps are more suitable for key/value pair data, which XML is not. Hence, Maps are not supported (out of the box) in JAXB binding library. It's not impossible to work with Maps, for example, but there are just no "natural" solutions.Paul Samsotha
@Paul I have able to partially fixed the issue by creating the wrapper class. But when I am trying to create the map of Map<String,BookBo> it seems to be failing. Do you know any reason why it is failing?Jinesh Parikh

1 Answers

0
votes

I am able to partially fix the issue by creating the below wrapper class.

import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;

    @XmlRootElement
    public class JaxrsMapWrapper<T,K> {

        private Map<T,K> map;

        public JaxrsMapWrapper(){

        }

        @Override
        public String toString() {
            return  map .toString();
        }

        public void setMap(Map<T,K> map) {
            this.map = map;
        }

        public Map<T,K> getMap() {
            return map;
        }
    }

By using the above class below getservice returning the typeof Map is working absolutly fine.

@GET
@Path("/mapWarpperReceive")
@Produces({MediaType.APPLICATION_XML})
public JaxrsMapWrapper<String,String> getWarpperMapMsgStr()
{

System.out.println("Returning the MapMessage as String ");
Map<String,String> originalMap=new  HashMap<String,String>(){{put("a","a");put("b","b");}};
JaxrsMapWrapper<String,String> jaxRsMapWrapper=new JaxrsMapWrapper<>();
jaxRsMapWrapper.setMap(originalMap);
return jaxRsMapWrapper;

}

But when I am trying to use the same class JaxrsMapWrapper with type of Map it is throwing Error 500 Internal server error while invoking through postman.

@GET
@Path("/customMap")
@Produces({MediaType.APPLICATION_XML})
public JaxrsMapWrapper<String,BookBo> getWarpperMapMsgWithCustomObject()
{
System.out.println("Returning the MapMessage as String and Custom Message ");
Map<String,BookBo> originalMap=new  HashMap<>();
originalMap.put("a",new BookBo(1,"Jinesh"));
JaxrsMapWrapper<String,BookBo> jaxRsMapWrapper=new JaxrsMapWrapper();
jaxRsMapWrapper.setMap(originalMap);
return jaxRsMapWrapper;
}

Below is the code for the User defined Java Object BookBo.

@XmlRootElement
public class BookBo implements Serializable{

    private Integer id;
    private String name;

    public BookBo() {

    }

    public BookBo(Integer id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    //getters and setters of the field
} 

What am I missing in the above code due to which while writing the Map in response is not working?