Anand
Anand

Reputation: 21310

Jersey rest service not returning XMLresponse

I am building a rest API using Jersey where XML and JSON outputs are allowed depending on what format client prefers(using Accept header).The service sends the below class as an output which looks like this

@XmlRootElement
public class ProjectDetails{

    private List<Attachment> attachments;
    private Map<String, List<Attachment>> imageCategory;

    @XmlTransient
    public List<Attachment> getAttachments() {
        return attachments;
    }

    public void setAttachments(List<Attachment> attachments) {
        this.attachments = attachments;
    }

    public Map<String, List<Attachment>> getImageCategory() {
        if(attachments == null || attachments.size() == 0){
            return null;
        }

        Map<String, List<Attachment>> map = new HashMap<String, List<Attachment>>();
        for (Attachment img : attachments){
            String key = img.getCategory();
            if(BaseUtil.hasText(key)){
                List<Attachment> values = map.get(key);
                if (values == null){
                    values = new ArrayList<Attachment>();
                }
                values.add(img);
                map.put(key, values);
            }
        }

        this.imageCategory = map ;
        return imageCategory;
    }

    public void setImageCategory(Map<String, List<Attachment>> imageCategory) {
        this.imageCategory = imageCategory;
    }
}

I don't want attachments field as an output so marked it with @XmlTransient rather I want to form a Map using the attachments field and send it as an output.

In case of JSON format, I am getting the correct response.But in case of XML, I am not getting any output when I hit the service.

I think it is related to this Map field because if I remove Map field and add some other field like String then I get that field in response.

Please let me know how to resolve this.

Update: After some googling, i found XmlAdapter solution and implemented as below

public class MapAdapter extends
        XmlAdapter<MapAdapter.AdaptedMap, Map<String, List<Attachment>>> {

    public static class AdaptedEntry {
        public String key;
        public List<Attachment> value = new ArrayList<Attachment>();
    }

    public static class AdaptedMap {
        List<AdaptedEntry> entries = new ArrayList<AdaptedEntry>();
    }

    @Override
    public AdaptedMap marshal(Map<String, List<Attachment>> map)
            throws Exception {
        AdaptedMap adaptedMap = new AdaptedMap();

        for (Entry<String, List<Attachment>> entry : map.entrySet()) {
            AdaptedEntry adaptedEntry = new AdaptedEntry();
            adaptedEntry.key = entry.getKey();
            adaptedEntry.value = entry.getValue();
            adaptedMap.entries.add(adaptedEntry);
        }
        return adaptedMap;
    }

    @Override
    public Map<String, List<Attachment>> unmarshal(AdaptedMap adaptedMap)
            throws Exception {
        List<AdaptedEntry> adapatedEntries = adaptedMap.entries;
        Map<String, List<Attachment>> map = new HashMap<String, List<Attachment>>(
                adapatedEntries.size());

        for (AdaptedEntry adaptedEntry : adapatedEntries) {
            map.put(adaptedEntry.key, adaptedEntry.value);
        }
        return map;
    }

And then

@XmlJavaTypeAdapter(MapAdapter.class)
    public Map<String, String> getImageCategory() {

But still it's not working..Anything I missed?

Upvotes: 2

Views: 631

Answers (1)

Pasupathi Rajamanickam
Pasupathi Rajamanickam

Reputation: 2052

I have used your ProjectDetails class a little bit changes I've made, and it provides response for both XML and JSON. Can you try this?

@XmlRootElement
public class ProjectDetails {
private List<Attachment> attachments;
private Map<String, ArrayList<Attachment>> imageCategory;

@XmlTransient
public List<Attachment> getAttachments() {
    return attachments;
}

public void setAttachments(List<Attachment> attachments) {
    this.attachments = attachments;
}
@XmlJavaTypeAdapter(MapAdapter.class) 
public Map<String, ArrayList<Attachment>> getImageCategory() {
    if(attachments == null || attachments.size() == 0){
        return null;
    }
    Map<String, ArrayList<Attachment>> map = new HashMap<String, ArrayList<Attachment>>();
    for (Attachment img : attachments){
        String key = img.getCategory();
        if(!key.equals("")){
            ArrayList<Attachment> values = map.get(key);
            if (values == null){
                values = new ArrayList<Attachment>();
            }
            values.add(img);
            map.put(key, values);
        }
    }

    this.imageCategory = map ;
    return imageCategory;
}

public void setImageCategory(Map<String, ArrayList<Attachment>> imageCategory) {
    this.imageCategory = imageCategory;
}

}

And the Adapter class you can use the following

public class MapAdapter extends XmlAdapter<MapElement[], Map<String, ArrayList<Attachment>>>{
public MapElement[] marshal(Map<String, ArrayList<Attachment>> arg0) throws Exception {
    MapElement[] mapElements = new MapElement[arg0.size()];
    int i = 0;
    for (Map.Entry<String, ArrayList<Attachment>> entry : arg0.entrySet()){
        mapElements[i++] = new MapElement(entry.getKey(), entry.getValue());
    }
    return mapElements;
}

public Map<String, ArrayList<Attachment>> unmarshal(MapElement[] arg0) throws Exception {
    Map<String, ArrayList<Attachment>> r = new HashMap<String, ArrayList<Attachment>>();
    for (MapElement mapelement : arg0)
        r.put(mapelement.key, mapelement.value);
    return r;
}

}

I've changed the MapElement also

public class MapElement {
@XmlElement
public String key;
@XmlElement
public ArrayList<Attachment> value;

private MapElement() {
}

public MapElement(String key, ArrayList<Attachment> value) {
    this.key = key;
    this.value = value;
}
}

And the Attachement class should have getter setter methods

public class Attachment {
public String getCategory() {
    return category;
}
public void setCategory(String category) {
    this.category = category;
}
private String category;
public Attachment(String cat){
    this.category = cat;
}

}

Upvotes: 2

Related Questions