-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Jref serialization and deserialization impl #6014
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 10 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
06c5bcb
Initial checkin of JRefValueDeserializer/JRefResolver
scottslewis 2e59cee
Added JRefSetter and JRefSetterFunction types, simplified JRefPath and
scottslewis d7e2e6b
Removed JRefSetter and JRefSetterFunction in favor of new SetterFunction
scottslewis 805fc1b
Added support in ValueDeserializerModifier for using
scottslewis 962e0f2
Merge branch 'FasterXML:3.x' into jref_deserialization
scottslewis 36ef70c
Added jref handling to StringCollectionDeserializer. Added test case
scottslewis fbc2d63
Added test cases for Double, Float, Boolean, and String handling in
scottslewis d038844
Added more (passing) test cases
scottslewis 5fd7a24
Refactored for simplicity. Added string constants for "$ref" and
scottslewis dfe1eb2
Merge branch '3.x' into jref_deserialization
scottslewis 3416b68
Refactoring for simplification.
scottslewis 42efbaa
Merge branch 'jref_deserialization' of https://github.com/scottslewis…
scottslewis 3854fe9
Merge branch '3.x' into jref_deserialization
scottslewis f8e8a4d
Refactoring as per discussion on pr #6014
scottslewis 8589262
Merge branch 'jref_deserialization' of https://github.com/scottslewis…
scottslewis 203ad96
Merge branch '3.x' into jref_deserialization
scottslewis ac4ea69
Merge branch '3.x' into jref_deserialization
scottslewis 4746244
Merge branch '3.x' into jref_deserialization
cowtowncoder cfe2bbf
Fix for comment
scottslewis 106a93a
Fix for comment
scottslewis 26f93d9
Changed JRefResolveException into DatabindException subclass (rather
scottslewis 99ed93c
Merge branch 'jref_deserialization' of https://github.com/scottslewis…
scottslewis 9f4b06f
API simplification
scottslewis 63b6646
Added jref tests package. Created JRefBeanPublicMemberDeserializerTest
scottslewis 52b1ddb
Added JRefSerializer class to build jrefs from original OG
scottslewis b0c4a3d
Backup of node work
scottslewis 76f8765
Added JRefValueSerializerModifier and appropriate JRefValueSerializer
scottslewis 6e7f70b
Merge branch '3.x' into jref_deserialization
scottslewis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,226 @@ | ||
| package tools.jackson.databind; | ||
|
|
||
| import java.util.List; | ||
| import java.util.function.Function; | ||
|
|
||
| import tools.jackson.core.JacksonException; | ||
| import tools.jackson.core.JsonParser; | ||
| import tools.jackson.core.JsonToken; | ||
| import tools.jackson.databind.BeanDescription.Supplier; | ||
| import tools.jackson.databind.deser.BeanDeserializerBuilder; | ||
| import tools.jackson.databind.deser.ValueDeserializerModifier; | ||
| import tools.jackson.databind.deser.std.DelegatingDeserializer; | ||
| import tools.jackson.databind.introspect.BeanPropertyDefinition; | ||
| import tools.jackson.databind.jsontype.TypeDeserializer; | ||
| import tools.jackson.databind.module.SimpleModule; | ||
| import tools.jackson.databind.node.ObjectNode; | ||
| import tools.jackson.databind.node.TreeTraversingParser; | ||
| import tools.jackson.databind.type.ArrayType; | ||
| import tools.jackson.databind.type.CollectionLikeType; | ||
| import tools.jackson.databind.type.CollectionType; | ||
| import tools.jackson.databind.type.MapLikeType; | ||
| import tools.jackson.databind.type.MapType; | ||
| import tools.jackson.databind.type.ReferenceType; | ||
|
|
||
| public class JRefModule extends SimpleModule { | ||
|
|
||
| private static final long serialVersionUID = 1L; | ||
|
|
||
| public JRefModule() { | ||
| super("JRef"); | ||
| } | ||
|
|
||
| protected class JRefValueDeserializerModifier extends ValueDeserializerModifier { | ||
|
|
||
| private static final long serialVersionUID = 1L; | ||
|
|
||
| protected ValueDeserializer<?> makeJRefValueDeserializer(DeserializationConfig config, JavaType jt, | ||
| Supplier beanDescRef, ValueDeserializer<?> d) { | ||
| return new JRefValueDeserializer(d); | ||
| } | ||
|
|
||
| @Override | ||
| public ValueDeserializer<?> modifyArrayDeserializer(DeserializationConfig config, ArrayType valueType, | ||
| Supplier beanDescRef, ValueDeserializer<?> deserializer) { | ||
| return makeJRefValueDeserializer(config, valueType, beanDescRef, deserializer); | ||
| } | ||
|
|
||
| @Override | ||
| public ValueDeserializer<?> modifyCollectionDeserializer(DeserializationConfig config, CollectionType type, | ||
| Supplier beanDescRef, ValueDeserializer<?> deserializer) { | ||
| return makeJRefValueDeserializer(config, type, beanDescRef, deserializer); | ||
| } | ||
|
|
||
| @Override | ||
| public ValueDeserializer<?> modifyEnumDeserializer(DeserializationConfig config, JavaType type, | ||
| Supplier beanDescRef, ValueDeserializer<?> deserializer) { | ||
| return makeJRefValueDeserializer(config, type, beanDescRef, deserializer); | ||
| } | ||
|
|
||
| @Override | ||
| public ValueDeserializer<?> modifyCollectionLikeDeserializer(DeserializationConfig config, | ||
| CollectionLikeType type, Supplier beanDescRef, ValueDeserializer<?> deserializer) { | ||
| return makeJRefValueDeserializer(config, type, beanDescRef, deserializer); | ||
| } | ||
|
|
||
| @Override | ||
| public ValueDeserializer<?> modifyDeserializer(DeserializationConfig config, Supplier beanDescRef, | ||
| ValueDeserializer<?> deserializer) { | ||
| return makeJRefValueDeserializer(config, null, beanDescRef, deserializer); | ||
| } | ||
|
|
||
| @Override | ||
| public KeyDeserializer modifyKeyDeserializer(DeserializationConfig config, JavaType type, | ||
| KeyDeserializer deserializer) { | ||
| return super.modifyKeyDeserializer(config, type, deserializer); | ||
| } | ||
|
|
||
| @Override | ||
| public ValueDeserializer<?> modifyMapDeserializer(DeserializationConfig config, MapType type, | ||
| Supplier beanDescRef, ValueDeserializer<?> deserializer) { | ||
| return makeJRefValueDeserializer(config, type, beanDescRef, deserializer); | ||
| } | ||
|
|
||
| @Override | ||
| public ValueDeserializer<?> modifyMapLikeDeserializer(DeserializationConfig config, MapLikeType type, | ||
| Supplier beanDescRef, ValueDeserializer<?> deserializer) { | ||
| return makeJRefValueDeserializer(config, type, beanDescRef, deserializer); | ||
| } | ||
|
|
||
| @Override | ||
| public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, Supplier beanDescRef, | ||
| BeanDeserializerBuilder builder) { | ||
| return super.updateBuilder(config, beanDescRef, builder); | ||
| } | ||
|
|
||
| @Override | ||
| public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config, Supplier beanDescRef, | ||
| List<BeanPropertyDefinition> propDefs) { | ||
| return super.updateProperties(config, beanDescRef, propDefs); | ||
| } | ||
|
|
||
| @Override | ||
| public ValueDeserializer<?> modifyReferenceDeserializer(DeserializationConfig config, ReferenceType type, | ||
| Supplier beanDescRef, ValueDeserializer<?> deserializer) { | ||
| return super.modifyReferenceDeserializer(config, type, beanDescRef, deserializer); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void setupModule(SetupContext context) { | ||
| super.setupModule(context); | ||
| context.addDeserializerModifier(new JRefValueDeserializerModifier()); | ||
| } | ||
|
|
||
| public static class JRefValueDeserializer extends DelegatingDeserializer { | ||
|
|
||
| void trace(String method, JRefValueDeserializer vds) { | ||
| System.out.println(new StringBuffer(method).append(".").append(vds.toString().toString())); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "JRefValueDeserializer[delegate=" + _delegatee + ", class=" + _valueClass + "]"; | ||
| } | ||
|
|
||
| void trace(String method) { | ||
| trace(method, this); | ||
| } | ||
|
|
||
| public JRefValueDeserializer(ValueDeserializer<?> src) { | ||
| super(src); | ||
| } | ||
|
|
||
| protected class JRefFindResult { | ||
| JRefPath jrefPath; | ||
| JsonParser parser; | ||
| } | ||
|
|
||
| protected TreeTraversingParser createTreeTraversingParser(JsonNode node) { | ||
| TreeTraversingParser result = new TreeTraversingParser(node); | ||
| result.nextToken(); | ||
| return result; | ||
| } | ||
|
|
||
| /** | ||
| * Find JRef in parser input stream. | ||
| * | ||
| * @param p JsonParser to use | ||
| * @param ctxt the current context | ||
| * @param typeDeserializer optional typeDeserializer | ||
| * @return JRefFindResult with JRefPath either set to non null (path found), or | ||
| * set to null (meaning that the further deserialization should be | ||
| * undertaken with the parse given in JRefFindResult | ||
| */ | ||
| protected JRefFindResult findJRef(JsonParser p, DeserializationContext ctxt, | ||
| TypeDeserializer typeDeserializer) { | ||
| JRefFindResult result = new JRefFindResult(); | ||
| JsonToken tok = p.currentToken(); | ||
| if (tok == JsonToken.START_OBJECT) { | ||
| JsonNode n = ctxt.readTree(p); | ||
| if (n instanceof ObjectNode) { | ||
| ObjectNode on = (ObjectNode) n; | ||
| JsonNode valNode = on.get(JRefPath.JREF_REF); | ||
| if (valNode != null) { | ||
| String valStr = valNode.asString(); | ||
| if (valStr != null) { | ||
| result.jrefPath = new JRefPath(valStr, ctxt, getDelegatee(), typeDeserializer); | ||
| result.parser = p; | ||
| return result; | ||
| } | ||
| // JREF_REF found, but no/null path. This is a syntax error | ||
| throw DatabindException.from(p, "JRefPath detected on stream but path is null", null); | ||
| } | ||
| } | ||
| result.parser = createTreeTraversingParser(n); | ||
| } else { | ||
| result.parser = p; | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| /** | ||
| * Deserialize with jref handling. Calls | ||
| * {@link #findJRef(JsonParser, DeserializationContext, TypeDeserializer)} to | ||
| * look on the parser stream for objects with 1 key == '$ref'. If found then the | ||
| * JRefPath is returned. If not found then the func arg is applied with the | ||
| * appropriate parser returned in JRefFindResult.parser field. | ||
| * | ||
| * @param p | ||
| * @param ctxt | ||
| * @param typeDeserializer | ||
| * @param func | ||
| * @return | ||
| */ | ||
| protected Object deserializerWithJRef(JsonParser p, DeserializationContext ctxt, | ||
| TypeDeserializer typeDeserializer, Function<JsonParser, Object> func) { | ||
| Object result = null; | ||
| JRefFindResult findResult = findJRef(p, ctxt, typeDeserializer); | ||
| if (findResult.jrefPath != null) { | ||
| result = findResult.jrefPath; | ||
| } else { | ||
| result = func.apply(findResult.parser); | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| @Override | ||
| public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) | ||
| throws JacksonException { | ||
| return deserializerWithJRef(p, ctxt, typeDeserializer, | ||
| ps -> super.deserializeWithType(ps, ctxt, typeDeserializer)); | ||
| } | ||
|
|
||
| @Override | ||
| public Object deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException { | ||
| return deserializerWithJRef(p, ctxt, null, ps -> super.deserialize(ps, ctxt)); | ||
| } | ||
|
|
||
| @Override | ||
| protected ValueDeserializer<?> newDelegatingInstance(ValueDeserializer<?> newDelegatee) { | ||
| return new JRefValueDeserializer(newDelegatee); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| package tools.jackson.databind; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| import tools.jackson.databind.jsontype.TypeDeserializer; | ||
|
|
||
| public class JRefPath { | ||
|
|
||
| public static final String JREF_REF = "$ref"; | ||
| private final DeserializationContext ctxt; | ||
| private final String path; | ||
| private final ValueDeserializer<?> deserializer; | ||
| private final TypeDeserializer typeDeserializer; | ||
|
|
||
| public JRefPath(String path, DeserializationContext ctxt, ValueDeserializer<?> deserializer, | ||
| TypeDeserializer typeDeserializer) { | ||
| Objects.requireNonNull(path, "path cannot be null"); | ||
| this.path = path; | ||
| Objects.requireNonNull(ctxt, "ctxt cannot be null"); | ||
| this.ctxt = ctxt; | ||
| Objects.requireNonNull(deserializer, "deserializer cannot be null"); | ||
| this.deserializer = deserializer; | ||
| this.typeDeserializer = typeDeserializer; | ||
| } | ||
|
|
||
| public JRefPath(String path, DeserializationContext ctxt, ValueDeserializer<?> deserializer) { | ||
| this(path, ctxt, deserializer, null); | ||
| } | ||
|
|
||
| public DeserializationContext getContext() { | ||
| return this.ctxt; | ||
| } | ||
|
|
||
| public String getPath() { | ||
| return this.path; | ||
| } | ||
|
|
||
| public ValueDeserializer<?> getValueDeserializer() { | ||
| return deserializer; | ||
| } | ||
|
|
||
| public TypeDeserializer getTypeDeserializer() { | ||
| return typeDeserializer; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "JRefPath[ctxt=" + ctxt + ", path=" + path + ", deserializer=" + deserializer + ", typeDeserializer=" | ||
| + typeDeserializer + "]"; | ||
| } | ||
|
|
||
| } |
39 changes: 39 additions & 0 deletions
39
src/main/java/tools/jackson/databind/JRefResolveException.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package tools.jackson.databind; | ||
|
|
||
| public class JRefResolveException extends RuntimeException { | ||
|
|
||
| private static final long serialVersionUID = 1L; | ||
| private final JRefResolver resolver; | ||
| private final Object root; | ||
|
|
||
| public JRefResolveException(JRefResolver resolver, Object root, String message, Throwable cause) { | ||
| super(message, cause); | ||
| this.resolver = resolver; | ||
| this.root = root; | ||
| } | ||
|
|
||
| public JRefResolveException(JRefResolver resolver, Object root, String message) { | ||
| super(message); | ||
| this.resolver = resolver; | ||
| this.root = root; | ||
| } | ||
|
|
||
| public JRefResolveException(JRefResolver resolver, String message) { | ||
| this(resolver, null, message); | ||
| } | ||
|
|
||
| public JRefResolver getResolver() { | ||
| return this.resolver; | ||
| } | ||
|
|
||
| public Object getRoot() { | ||
| return this.root; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "JRefResolveException [resolver=" + resolver + ", root=" + root + ", message=" + super.getMessage() | ||
| + "]"; | ||
| } | ||
|
|
||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.