Last active
February 23, 2016 01:15
-
-
Save mgius/aa4f2a54fbbcd348196a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import static org.junit.Assert.assertTrue; | |
import com.fasterxml.jackson.annotation.JsonProperty; | |
import com.fasterxml.jackson.databind.ObjectMapper; | |
import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | |
import org.junit.Test; | |
public class JacksonBugTest { | |
@Test // passes | |
public void testSerializeDefaultMapper() throws Exception { | |
ObjectMapper mapper = new ObjectMapper(); | |
Model model = new Model.Builder().withSomeValue("whatever").build(); | |
String json = mapper.writeValueAsString(model); | |
Model reconstructed = mapper.readValue(json, Model.class); | |
} | |
@Test // fails: Unrecognized field "someValue" | |
public void testSerializeSnakeCaseMapper() throws Exception { | |
ObjectMapper mapper = new ObjectMapper().setPropertyNamingStrategy( | |
PropertyNamingStrategy.SNAKE_CASE); | |
Model model = new Model.Builder().withSomeValue("whatever").build(); | |
String json = mapper.writeValueAsString(model); | |
// The serialized JSON includes someValue even though we serialized using SNAKE_CASE. | |
// However, if we change the JsonProperty on the constructor to any other string the field will | |
// be snake case serialized and this assertion will fail | |
assertTrue(json.contains("someValue")); | |
// This deserialize will fail because the mapper is looking for some_value, but someValue has | |
// been serialized instead. | |
Model reconstructed = mapper.readValue(json, Model.class); | |
} | |
// Use the builder to deserialize | |
@JsonDeserialize(builder = Model.Builder.class) | |
public static class Model { | |
private String someValue; | |
// Previously we used JsonCreator, and for whatever reason the JsonProperty lingered | |
// This JsonProperty has an unexpected affect on Serialization. | |
private Model(@JsonProperty("someValue") String matchingArgument) { | |
this.someValue = matchingArgument; | |
} | |
public String getSomeValue() { | |
return someValue; | |
} | |
public static class Builder { | |
private String someValue; | |
public Builder() { | |
} | |
public Builder withSomeValue(String someValue) { | |
this.someValue = someValue; | |
return this; | |
} | |
public Model build() { | |
return new Model(someValue); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.oracle.opc.nimbula.osawa.models; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertFalse; | |
import static org.junit.Assert.assertTrue; | |
import com.fasterxml.jackson.annotation.JsonCreator; | |
import com.fasterxml.jackson.annotation.JsonProperty; | |
import com.fasterxml.jackson.databind.ObjectMapper; | |
import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |
import org.apache.commons.lang3.builder.EqualsBuilder; | |
import org.apache.commons.lang3.builder.HashCodeBuilder; | |
import org.junit.Test; | |
public class JacksonBugTest { | |
private static final ObjectMapper mapper = new ObjectMapper().setPropertyNamingStrategy( | |
PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES); | |
@Test | |
public void testSerializeSnakeCaseMapper() throws Exception { | |
ModelA model = new ModelA("whatever"); | |
String json = mapper.writeValueAsString(model); | |
// The serialized JSON includes someValue even though we serialized using SNAKE_CASE. | |
// this is apparently expected because @JsonProperty on the constructor applies to serialization | |
assertTrue(json.contains("someValue")); | |
// This deserialize will pass because the mapper is looking for someValue, | |
// which was overridden implicitly by the JsonProperty in the constructor on ModelA | |
ModelA reconstructed = mapper.readValue(json, ModelA.class); | |
} | |
@Test | |
public void testSerializeModelB() throws Exception { | |
ModelB model = new ModelB("whatever"); | |
String json = mapper.writeValueAsString(model); | |
// The serialized JSON does not include someOtherValue, but instead contains some_value. | |
// Why does this behave differently depending on the value of @JsonProperty? | |
// Should not contain some_value, because of constructor annotation? | |
assertFalse(json.contains("some_value")); // fails | |
// Should contain someOtherValue, because of constructor annotation? | |
assertTrue(json.contains("someOtherValue")); // fails | |
// This also passes, but why should it? | |
// The explicit JsonProperty on the only constructor doesn't match the json string? And | |
// there isn't a no-args constructor nor a setter nor is the | |
ModelB reconstructed = mapper.readValue(json, ModelB.class); | |
// This passes, so the object is being reconstructed correctly. | |
assertEquals(model, reconstructed); | |
} | |
// Class with JsonProperty that matches field name | |
public static class ModelA { | |
private String someValue; | |
@JsonCreator | |
private ModelA(@JsonProperty("someValue") String matchingArgument) { | |
this.someValue = matchingArgument; | |
} | |
public String getSomeValue() { | |
return someValue; | |
} | |
} | |
// Class with JsonProperty that does not match field name | |
public static class ModelB { | |
private String someValue; | |
@JsonCreator | |
private ModelB(@JsonProperty("someOtherValue") String matchingArgument) { | |
this.someValue = matchingArgument; | |
} | |
public String getSomeValue() { | |
return someValue; | |
} | |
@Override | |
public boolean equals(Object obj) { | |
return EqualsBuilder.reflectionEquals(this, obj); | |
} | |
@Override | |
public int hashCode() { | |
return HashCodeBuilder.reflectionHashCode(this); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment