yann
yann

Reputation: 139

Deserialize JSON with Jackson without proper field

I've got this JSON : {"success":false}

I want to deserialize this into this POJO :

class Message {
    private Map<String, String> dataset = new HashMap<String, String>();

    @JsonProperty("success")
    public boolean isSuccess() {
        return Boolean.valueOf(dataset.get("success"));
    }

    @JsonProperty("success")
    public void setSuccess(boolean success) {
        dataset.put("success", String.valueOf(success));
    }
}

Is it possible to deserialize this JSON into a class without field success? So far, i've always got the "UnrecognizedPropertyException: Unrecognized field "success""

Thanks for your help!

Upvotes: 6

Views: 10339

Answers (3)

Programmer Bruce
Programmer Bruce

Reputation: 67023

I don't understand the question. Jackson will (de)serialize from/to the current version of the Message POJO you've defined in the original question just fine, without errors, and without any special configurations (other than the @JsonProperty annotations). The current Message POJO does not have a field named success, but it does define a property named success, which is why Jackson is happy to map the example JSON to it without any additional configurations. Are you wanting to remove the @JsonProperty annotations?

If that's the case, then you can do so, and Jackson will still (de)serialize from/to the Message POJO with the same example JSON without any other configurations necessary, because the isSuccess and setSuccess method signatures already adequately define that Message has a property named success, which matches the element name in the JSON.

The following examples demonstrate these points.

Example 1 with Message POJO exactly as defined in original question:

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonFoo
{
  public static void main(String[] args) throws Exception
  {
    // input: {"success":false}
    String inputJson = "{\"success\":false}";

    ObjectMapper mapper = new ObjectMapper();
    Message message = mapper.readValue(inputJson, Message.class);
    System.out.println(mapper.writeValueAsString(message));
    // output: {"success":false}
  }
}

class Message
{
  private Map<String, String> dataset = new HashMap<String, String>();

  @JsonProperty("success")
  public boolean isSuccess()
  {
    return Boolean.valueOf(dataset.get("success"));
  }

  @JsonProperty("success")
  public void setSuccess(boolean success)
  {
    dataset.put("success", String.valueOf(success));
  }
}

Example 2 with Message POJO modified to remove @JsonProperty annotations.

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonFoo
{
  public static void main(String[] args) throws Exception
  {
    // input: {"success":false}
    String inputJson = "{\"success\":false}";

    ObjectMapper mapper = new ObjectMapper();
    Message message = mapper.readValue(inputJson, Message.class);
    System.out.println(mapper.writeValueAsString(message));
    // output: {"success":false}
  }
}

class Message
{
  private Map<String, String> dataset = new HashMap<String, String>();

  public boolean isSuccess()
  {
    return Boolean.valueOf(dataset.get("success"));
  }

  public void setSuccess(boolean success)
  {
    dataset.put("success", String.valueOf(success));
  }
}

Example with MessageWrapper:

public class JacksonFoo
{
  public static void main(String[] args) throws Exception
  {
    // input: {"success":false}
    String inputJson = "{\"success\":true}";

    ObjectMapper mapper = new ObjectMapper();
    MessageWrapper wrappedMessage = mapper.readValue(inputJson, MessageWrapper.class);
    System.out.println(mapper.writeValueAsString(wrappedMessage));
    // output: {"success":true}
  }
}

class MessageWrapper
{
  @JsonUnwrapped
  @JsonProperty // exposes non-public field for Jackson use
  Message message;
}

Upvotes: 0

bdoughan
bdoughan

Reputation: 149057

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

If you can't get it to work with Jackson, below is how you can support this use case with MOXy.

Message

No annotations are required on the Message class. By default property access is used. You can specify field access using @XmlAccessorType(XmlAccessType.FIELD), see: http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html.

package forum11315389;

import java.util.*;

class Message {
    private Map<String, String> dataset = new HashMap<String, String>();

    public boolean isSuccess() {
        return Boolean.valueOf(dataset.get("success"));
    }

    public void setSuccess(boolean success) {
        dataset.put("success", String.valueOf(success));
    }
}

jaxb.properties

To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Demo

package forum11315389;

import java.io.StringReader;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String,Object> properties = new HashMap<String,Object>(1);
        properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
        properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
        JAXBContext jc = JAXBContext.newInstance(new Class[] {Message.class}, properties);

        StreamSource json = new StreamSource(new StringReader("{\"success\":false}"));
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Message message = unmarshaller.unmarshal(json, Message.class).getValue();

        Marshaller marshaller = jc.createMarshaller();
        marshaller.marshal(message, System.out);
    }

}

Input/Output

{"success":false}

Upvotes: 0

Francisco Spaeth
Francisco Spaeth

Reputation: 23913

You could implement a method and annotate it with @JsonAnySetter like this:

@JsonAnySetter
public void handleUnknownProperties(String key, Object value) {
    // this will be invoked when property isn't known
}

another possibility would be turn this fail off like this:

objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

This would let you deserialize your JSON without failing when properties are not found.

Test


public static class Message {
    private final Map<String, String> dataset = new HashMap<String, String>();

    @Override
    public String toString() {
        return "Message [dataset=" + dataset + "]";
    }

}

@Test
public void testJackson() throws JsonParseException, JsonMappingException, IOException {
    String json = "{\"success\":false}";
    ObjectMapper om = new ObjectMapper().configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    System.out.println(om.readValue(json, Message.class));
}

Upvotes: 6

Related Questions