This repository has been archived by the owner on Nov 7, 2019. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of github.com:FasterXML/jackson-datatype-jdk8
- Loading branch information
Showing
15 changed files
with
130 additions
and
128 deletions.
There are no files selected for viewing
This file contains 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
111 changes: 25 additions & 86 deletions
111
src/main/java/com/fasterxml/jackson/datatype/jdk8/OptionalDeserializer.java
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,126 +1,65 @@ | ||
package com.fasterxml.jackson.datatype.jdk8; | ||
|
||
import java.io.IOException; | ||
import java.util.Optional; | ||
|
||
import com.fasterxml.jackson.core.JsonParser; | ||
import com.fasterxml.jackson.core.JsonToken; | ||
import com.fasterxml.jackson.databind.*; | ||
import com.fasterxml.jackson.databind.deser.ContextualDeserializer; | ||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer; | ||
import com.fasterxml.jackson.databind.deser.ValueInstantiator; | ||
import com.fasterxml.jackson.databind.deser.std.ReferenceTypeDeserializer; | ||
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; | ||
|
||
final class OptionalDeserializer | ||
extends StdDeserializer<Optional<?>> | ||
implements ContextualDeserializer | ||
extends ReferenceTypeDeserializer<Optional<?>> | ||
{ | ||
private static final long serialVersionUID = 1L; | ||
|
||
protected final JavaType _fullType; | ||
|
||
protected final JsonDeserializer<?> _valueDeserializer; | ||
protected final TypeDeserializer _valueTypeDeserializer; | ||
|
||
/* | ||
/********************************************************** | ||
/* Life-cycle | ||
/********************************************************** | ||
*/ | ||
|
||
public OptionalDeserializer(JavaType fullType, | ||
TypeDeserializer typeDeser, JsonDeserializer<?> valueDeser) | ||
{ | ||
super(fullType); | ||
_fullType = fullType; | ||
_valueTypeDeserializer = typeDeser; | ||
_valueDeserializer = valueDeser; | ||
} | ||
|
||
/** | ||
* Overridable fluent factory method used for creating contextual | ||
* instances. | ||
* @since 2.9 | ||
*/ | ||
protected OptionalDeserializer withResolved(TypeDeserializer typeDeser, | ||
JsonDeserializer<?> valueDeser) | ||
public OptionalDeserializer(JavaType fullType, ValueInstantiator inst, | ||
TypeDeserializer typeDeser, JsonDeserializer<?> deser) | ||
{ | ||
if ((valueDeser == _valueDeserializer) && (typeDeser == _valueTypeDeserializer)) { | ||
return this; | ||
} | ||
return new OptionalDeserializer(_fullType, typeDeser, valueDeser); | ||
} | ||
|
||
/** | ||
* Method called to finalize setup of this deserializer, | ||
* after deserializer itself has been registered. This | ||
* is needed to handle recursive and transitive dependencies. | ||
*/ | ||
@Override | ||
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, | ||
BeanProperty property) throws JsonMappingException | ||
{ | ||
JsonDeserializer<?> deser = _valueDeserializer; | ||
TypeDeserializer typeDeser = _valueTypeDeserializer; | ||
JavaType refType = _fullType.getReferencedType(); | ||
|
||
if (deser == null) { | ||
deser = ctxt.findContextualValueDeserializer(refType, property); | ||
} else { // otherwise directly assigned, probably not contextual yet: | ||
deser = ctxt.handleSecondaryContextualization(deser, property, refType); | ||
} | ||
if (typeDeser != null) { | ||
typeDeser = typeDeser.forProperty(property); | ||
} | ||
return withResolved(typeDeser, deser); | ||
super(fullType, inst, typeDeser, deser); | ||
} | ||
|
||
/* | ||
/********************************************************** | ||
/* Overridden accessors | ||
/* Abstract method implementations | ||
/********************************************************** | ||
*/ | ||
|
||
@Override | ||
public JavaType getValueType() { return _fullType; } | ||
public OptionalDeserializer withResolved(TypeDeserializer typeDeser, JsonDeserializer<?> valueDeser) { | ||
return new OptionalDeserializer(_fullType, _valueInstantiator, | ||
typeDeser, valueDeser); | ||
} | ||
|
||
@Override | ||
public Optional<?> getNullValue(DeserializationContext ctxt) { | ||
return Optional.empty(); | ||
} | ||
|
||
/* | ||
/********************************************************** | ||
/* Deserialization | ||
/********************************************************** | ||
*/ | ||
|
||
@Override | ||
public Optional<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException | ||
{ | ||
Object refd = (_valueTypeDeserializer == null) | ||
? _valueDeserializer.deserialize(p, ctxt) | ||
: _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer); | ||
return Optional.ofNullable(refd); | ||
public Optional<?> referenceValue(Object contents) { | ||
return Optional.ofNullable(contents); | ||
} | ||
|
||
@Override | ||
public Optional<?> deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) | ||
throws IOException | ||
{ | ||
final JsonToken t = p.getCurrentToken(); | ||
if (t == JsonToken.VALUE_NULL) { | ||
return getNullValue(ctxt); | ||
} | ||
// 03-Nov-2013, tatu: This gets rather tricky with "natural" types | ||
// (String, Integer, Boolean), which do NOT include type information. | ||
// These might actually be handled ok except that nominal type here | ||
// is `Optional`, so special handling is not invoked; instead, need | ||
// to do a work-around here. | ||
// 22-Oct-2015, tatu: Most likely this is actually wrong, result of incorrect | ||
// serialization (up to 2.6, was omitting necessary type info after all); | ||
// but safest to leave in place for now | ||
if (t != null && t.isScalarValue()) { | ||
return deserialize(p, ctxt); | ||
} | ||
return (Optional<?>) typeDeserializer.deserializeTypedFromAny(p, ctxt); | ||
public Object getReferenced(Optional<?> reference) { | ||
return reference.get(); | ||
} | ||
|
||
@Override // since 2.9 | ||
public Optional<?> updateReference(Optional<?> reference, Object contents) { | ||
return Optional.ofNullable(contents); | ||
} | ||
|
||
// Default ought to be fine: | ||
// public Boolean supportsUpdate(DeserializationConfig config) { } | ||
|
||
} |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
71 changes: 71 additions & 0 deletions
71
src/test/java/com/fasterxml/jackson/datatype/jdk8/optional/OptionalMergingTest.java
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package com.fasterxml.jackson.datatype.jdk8.optional; | ||
|
||
import java.util.Optional; | ||
|
||
import com.fasterxml.jackson.annotation.JsonSetter; | ||
import com.fasterxml.jackson.annotation.OptBoolean; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.datatype.jdk8.ModuleTestBase; | ||
|
||
public class OptionalMergingTest extends ModuleTestBase | ||
{ | ||
static class MergedStringReference | ||
{ | ||
@JsonSetter(merge=OptBoolean.TRUE) | ||
public Optional<String> value = Optional.of("default"); | ||
} | ||
|
||
static class MergedPOJOReference | ||
{ | ||
@JsonSetter(merge=OptBoolean.TRUE) | ||
public Optional<POJO> value; | ||
|
||
protected MergedPOJOReference() { | ||
value = Optional.of(new POJO(7, 2)); | ||
} | ||
|
||
public MergedPOJOReference(int x, int y) { | ||
value = Optional.of(new POJO(x, y)); | ||
} | ||
} | ||
|
||
static class POJO { | ||
public int x, y; | ||
|
||
protected POJO() { } | ||
public POJO(int x, int y) { | ||
this.x = x; | ||
this.y = y; | ||
} | ||
} | ||
|
||
/* | ||
/********************************************************************** | ||
/* Test methods | ||
/********************************************************************** | ||
*/ | ||
|
||
private final ObjectMapper MAPPER = mapperWithModule(); | ||
|
||
public void testStringReferenceMerging() throws Exception | ||
{ | ||
MergedStringReference result = MAPPER.readValue(aposToQuotes("{'value':'override'}"), | ||
MergedStringReference.class); | ||
assertEquals("override", result.value.get()); | ||
} | ||
|
||
public void testPOJOReferenceMerging() throws Exception | ||
{ | ||
MergedPOJOReference result = MAPPER.readValue(aposToQuotes("{'value':{'y':-6}}"), | ||
MergedPOJOReference.class); | ||
assertEquals(7, result.value.get().x); | ||
assertEquals(-6, result.value.get().y); | ||
|
||
// Also should retain values we pass | ||
result = MAPPER.readerForUpdating(new MergedPOJOReference(10, 20)) | ||
.readValue(aposToQuotes("{'value':{'x':11}}")); | ||
assertEquals(11, result.value.get().x); | ||
assertEquals(20, result.value.get().y); | ||
} | ||
} |
Oops, something went wrong.