Ted
Ted

Reputation: 20184

Jackson throws JsonMappingException on deserialize; demands single-String constructor?

Another question, but it relates to this one: Deserializing JSON with Jackson - Why JsonMappingException "No suitable constructor"?

This time I am getting a different error, namely that the Jackson deserializer complains that I do not have a "single-String constructor/factory method" in my class ProtocolContainer.

However, if I add a single-String constructor, like this:

public ProtocolContainer(String json) {}

the exception does indeed disappear, but the ProtocolContainer that I expected to be there is all "empty", i.e. all its properties are in their initial state, and not populated according to the JSON-string.

Why is that?

I'm pretty sure you shouldn't need a single-String constructor, and if you do that you should not have to populate the properties in that constructor, right?

=)

Upvotes: 11

Views: 40303

Answers (4)

GreenGiant
GreenGiant

Reputation: 5256

I had the same problem. For me, the solution was to switch from passing a String to the convertValue method, to an InputStream to the readValue method:

// Instead of this:
String jsonString = "..."
ProtocolContainer pc = mapper.convertValue(jsonString, ProtocolContainer.class);

// ... do this:
String jsonString = "..."
InputStream is = new StringInputStream(jsonString);
ProtocolContainer pc = mapper.readValue(is, ProtocolContainer.class);

Upvotes: 1

Ted
Ted

Reputation: 20184

Oh, so once again I found out the answer AFTER I posted this question (even though I tried a lot of things before posting).

What I did to solve this was to use the @JsonCreator annotation. I simply annotated my static Create method, like this:

@JsonCreator
public static ProtocolContainer Create(String jsonString)
{

    ProtocolContainer pc = null;
    try {
        pc = mapper.readValue(jsonString, ProtocolContainer.class);
    } catch (JsonParseException|JsonMappingException|IOException e) {
        // handle
    }

    return pc;
}

And then problem solved.

Upvotes: 19

Seba Cervantes
Seba Cervantes

Reputation: 329

It seems that you are sending to the server a string instead of an object.

Instead of sending the string to be parsed on the server side, you can do it easier just by sending JSON.parse(stringObject), and Jackson will deserialize it normally as expected.

Upvotes: -1

StaxMan
StaxMan

Reputation: 116630

The exception suggests that the JSON value you have is a String, something like:

{ "protocol" : "http" }

or perhaps "double-quoted JSON":

"\"{\"property\":\"value\"}\"

when trying to bind like:

ProtocolContainer p = mapper.readValue(json, ProtocolContainer.class);

in which case Jackson has no properties to map, just a String. And in that case it does indeed require either a custom deserializer, or a creator method. Creator methods are either single-string-argument constructors, or single-string argument static methods: the difference being that only constructors can be auto-detected (this is just a practical short-cut as there can only be one such constructor, but multiple static methods).

Your solution does indeed work, just thought I'd give some background as to what is happening.

Reading through it second time it seems more likely you have double-quoted stuff (JSON in JSON): another thing to consider is to get plain JSON, if possible. But maybe that's hard to do.

Upvotes: 18

Related Questions