Eunito
Eunito

Reputation: 436

Spring - HttpMessageConversionException using ResponseEntity with Map<String,JSONobject>

I'm facing an issue regarding the acess to a JSONobject inside a Map<String,JSONobject>.

Basically I'm trying to build a Json reply in a controller method like this:

{
    "item1": {
        "type1": 2,
        "type5": 1
    },
    "item6": {
        "type3": 32,
        "type26": 7,
        "type5": 9
        (being the number of keys inside of each key/value an object with several key/value entries)
    }
}

This is the controller:

@PostMapping(value="/endpoint")
    public ResponseEntity<?> aggData(@RequestBody List<ValidNum> nums){
        try {
            Map<String, JSONObject> data = dataService.aggData(numsData);
            AggSuccess callSuccessResp = new AggSuccess(data);
            return new ResponseEntity<>(callSuccessResp, HttpStatus.OK);
        } catch (Error e) {
            AggError callErrorResp = new AggError(e.getMessage());
            return new ResponseEntity<AggregatedDataError>(callErrorResp, HttpStatus.BAD_REQUEST);
        }
    }

This is the service implementation

@Override
    public Map<String,JSONObject> aggregateData(List<ValidNum> numsData) {
        Map<String,JSONObject> aggData = new HashMap<>();

        for (ValidNum vn : numsData) {

            if (aggData.get(vn.item) == null) {
                JSONObject itemTypesCount = new JSONObject();
                aggData.put(vn.item, itemTypesCount.put(vn.type, 1));
            } else {
                JSONObject itemData = aggData.get(vn.item);
                Long typeValue  = (Long) itemData.get(vn.type);
                itemData.put(vn.type, typeValue+1);
                aggData.put(vn.item, itemData);
            }
        }

        return aggData;
    }

The ValidNum class

public class ValidNum {

    public String nr;
    public String item;
    public String type;

    public ValidNumber(String nr, String item, String type) {
        this.nr = nr;
        this.item = item;
        this.type = type;
    }

}

The AggSuccess response class (where I think problem is)

public class AggSuccess {
    public Map<String,JSONObject> aggSuccess;

    public AggSuccess(Map<String, JSONObject> aggSuccess) {
        this.aggSuccess = aggSuccess;
    }

}

The problem is that I'm allways getting an error unless I add this to the application properties: spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false and I don't want that because I don't wan't data to look like this:

{
    "item1": {},
    "item6": {}
}

Commenting that entry I get the following error:

ERROR 26551 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.json.JSONObject]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.json.JSONObject and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: package.AggDataSuccess["aggSuccess"]->java.util.HashMap["item1"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.json.JSONObject and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: package.AggDataSuccess["aggSuccess"]->java.util.HashMap["item1"])

and the weirdest part is the fact that debugging in the controller's callSuccessResp, right before sending data back to postman, I get the correct json value:

{
    "item1": {
        "type1": 2,
        "type5": 1
    },
    "item6": {
        "type3": 32,
        "type26": 7,
        "type5": 9
    }
}

So, what can I do to get the response entity to read and serialize the JSONobject properly?

Upvotes: 0

Views: 4084

Answers (2)

SanketKD
SanketKD

Reputation: 1531

Add default constructors in models to support deserialization

Upvotes: 1

Davipb
Davipb

Reputation: 151

Jackson doesn't support org.json classes by default. Try to build your JSON Object using Jackson's com.fasterxml.jackson.databind.node.ObjectNode instead.

Upvotes: 1

Related Questions