Skip to content

Commit 958677f

Browse files
committed
Merge branch '2.14' into 2.15
2 parents 792a60b + 0020fcb commit 958677f

File tree

4 files changed

+283
-4
lines changed

4 files changed

+283
-4
lines changed

release-notes/CREDITS-2.x

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,10 @@ Moritz Halbritter (mhalbritter@github)
15291529
from 2.13.x to 2.14.0
15301530
(2.14.1)
15311531
1532+
Philippe Marschall (marschall@github)
1533+
* Contributed #3699: Allow custom `JsonNode` implementations
1534+
(2.14.2)
1535+
15321536
Hervé Boutemy (hboutemy@github)
15331537
* Contributed fix for #3680: Timestamp in classes inside jar showing 02/01/1980
15341538
(2.15.0)

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Project: jackson-databind
1717

1818
#1751: `@JsonTypeInfo` does not work if the Type Id is an Integer value
1919
(reported by @marvin-we)
20+
#3699: Allow custom `JsonNode` implementations
21+
(contributed by Philippe M)
2022

2123
2.14.1 (21-Nov-2022)
2224

src/main/java/com/fasterxml/jackson/databind/node/NodeCursor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ protected final static class ObjectCursor
195195
public ObjectCursor(JsonNode n, NodeCursor p)
196196
{
197197
super(JsonStreamContext.TYPE_OBJECT, p);
198-
_contents = ((ObjectNode) n).fields();
198+
_contents = n.fields();
199199
_needEntry = true;
200200
}
201201

src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java

Lines changed: 276 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.IOException;
44
import java.io.StringWriter;
55
import java.util.*;
6+
import java.util.Map.Entry;
67

78
import com.fasterxml.jackson.annotation.JsonCreator;
89
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -16,8 +17,11 @@
1617
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
1718
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
1819
import com.fasterxml.jackson.databind.json.JsonMapper;
20+
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
1921
import com.fasterxml.jackson.databind.node.ArrayNode;
22+
import com.fasterxml.jackson.databind.node.BaseJsonNode;
2023
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
24+
import com.fasterxml.jackson.databind.node.JsonNodeType;
2125
import com.fasterxml.jackson.databind.node.ObjectNode;
2226

2327
public class ObjectReaderTest extends BaseMapTest
@@ -519,17 +523,286 @@ public boolean handleUnknownProperty(DeserializationContext ctxt, JsonParser p,
519523
return true;
520524
}
521525
}).build();
522-
A aObject = mapper.readValue("{\"unknownField\" : 1, \"knownField\": \"test\"}", A.class);
526+
A2297 aObject = mapper.readValue("{\"unknownField\" : 1, \"knownField\": \"test\"}",
527+
A2297.class);
523528

524529
assertEquals("test", aObject.knownField);
525530
}
526531

527-
private static class A {
532+
// For [databind#2297]
533+
private static class A2297 {
528534
String knownField;
529535

530536
@JsonCreator
531-
private A(@JsonProperty("knownField") String knownField) {
537+
private A2297(@JsonProperty("knownField") String knownField) {
532538
this.knownField = knownField;
533539
}
534540
}
541+
542+
// [databind#3699]: custom object node classes
543+
public void testCustomObjectNode() throws Exception
544+
{
545+
ObjectNode defaultNode = (ObjectNode) MAPPER.readTree("{\"x\": 1, \"y\": 2}");
546+
CustomObjectNode customObjectNode = new CustomObjectNode(defaultNode);
547+
Point point = MAPPER.readerFor(Point.class).readValue(customObjectNode);
548+
assertEquals(1, point.x);
549+
assertEquals(2, point.y);
550+
}
551+
552+
// [databind#3699]: custom array node classes
553+
public void testCustomArrayNode() throws Exception
554+
{
555+
ArrayNode defaultNode = (ArrayNode) MAPPER.readTree("[{\"x\": 1, \"y\": 2}]");
556+
DelegatingArrayNode customArrayNode = new DelegatingArrayNode(defaultNode);
557+
Point[] points = MAPPER.readerFor(Point[].class).readValue(customArrayNode);
558+
Point point = points[0];
559+
assertEquals(1, point.x);
560+
assertEquals(2, point.y);
561+
}
562+
563+
// for [databind#3699]
564+
static class CustomObjectNode extends BaseJsonNode
565+
{
566+
private static final long serialVersionUID = 1L;
567+
568+
private final ObjectNode _delegate;
569+
570+
CustomObjectNode(ObjectNode delegate) {
571+
this._delegate = delegate;
572+
}
573+
574+
@Override
575+
public boolean isObject() {
576+
return true;
577+
}
578+
579+
@Override
580+
public int size() {
581+
return _delegate.size();
582+
}
583+
584+
@Override
585+
public Iterator<Entry<String, JsonNode>> fields() {
586+
return _delegate.fields();
587+
}
588+
589+
@Override
590+
public Iterator<JsonNode> elements() {
591+
return Collections.emptyIterator();
592+
}
593+
594+
@Override
595+
public JsonToken asToken() {
596+
return JsonToken.START_OBJECT;
597+
}
598+
599+
@Override
600+
public void serialize(JsonGenerator g, SerializerProvider ctxt) {
601+
// ignore, will not be called
602+
}
603+
604+
@Override
605+
public void serializeWithType(JsonGenerator g, SerializerProvider ctxt, TypeSerializer typeSer) {
606+
// ignore, will not be called
607+
}
608+
609+
@Override
610+
@SuppressWarnings("unchecked")
611+
public <T extends JsonNode> T deepCopy() {
612+
return (T) new CustomObjectNode(_delegate);
613+
}
614+
615+
@Override
616+
public JsonNode get(int index) {
617+
return null;
618+
}
619+
620+
@Override
621+
public JsonNode path(String fieldName) {
622+
return null;
623+
}
624+
625+
@Override
626+
public JsonNode path(int index) {
627+
return null;
628+
}
629+
630+
@Override
631+
protected JsonNode _at(JsonPointer ptr) {
632+
return null;
633+
}
634+
635+
@Override
636+
public JsonNodeType getNodeType() {
637+
return JsonNodeType.OBJECT;
638+
}
639+
640+
@Override
641+
public String asText() {
642+
return "";
643+
}
644+
645+
@Override
646+
public JsonNode findValue(String fieldName) {
647+
return null;
648+
}
649+
650+
@Override
651+
public JsonNode findParent(String fieldName) {
652+
return null;
653+
}
654+
655+
@Override
656+
public List<JsonNode> findValues(String fieldName, List<JsonNode> foundSoFar) {
657+
return Collections.emptyList();
658+
}
659+
660+
@Override
661+
public List<String> findValuesAsText(String fieldName, List<String> foundSoFar) {
662+
return foundSoFar;
663+
}
664+
665+
@Override
666+
public List<JsonNode> findParents(String fieldName, List<JsonNode> foundSoFar) {
667+
return foundSoFar;
668+
}
669+
670+
@Override
671+
public boolean equals(Object o) {
672+
if (o == this) {
673+
return true;
674+
}
675+
if (!(o instanceof CustomObjectNode)) {
676+
return false;
677+
}
678+
CustomObjectNode other = (CustomObjectNode) o;
679+
return this._delegate.equals(other._delegate);
680+
}
681+
682+
@Override
683+
public int hashCode() {
684+
return _delegate.hashCode();
685+
}
686+
687+
}
688+
689+
// for [databind#3699]
690+
static class DelegatingArrayNode extends BaseJsonNode
691+
{
692+
private static final long serialVersionUID = 1L;
693+
694+
private final ArrayNode _delegate;
695+
696+
DelegatingArrayNode(ArrayNode delegate) {
697+
this._delegate = delegate;
698+
}
699+
700+
@Override
701+
public boolean isArray() {
702+
return true;
703+
}
704+
705+
@Override
706+
public int size() {
707+
return _delegate.size();
708+
}
709+
710+
@Override
711+
public Iterator<JsonNode> elements() {
712+
return _delegate.elements();
713+
}
714+
715+
@Override
716+
public JsonToken asToken() {
717+
return JsonToken.START_ARRAY;
718+
}
719+
720+
@Override
721+
public void serialize(JsonGenerator g, SerializerProvider ctxt) {
722+
// ignore, will not be called
723+
}
724+
725+
@Override
726+
public void serializeWithType(JsonGenerator g, SerializerProvider ctxt, TypeSerializer typeSer) {
727+
// ignore, will not be called
728+
}
729+
730+
@Override
731+
@SuppressWarnings("unchecked")
732+
public <T extends JsonNode> T deepCopy() {
733+
return (T) new DelegatingArrayNode(_delegate);
734+
}
735+
736+
@Override
737+
public JsonNode get(int index) {
738+
return _delegate.get(index);
739+
}
740+
741+
@Override
742+
public JsonNode path(String fieldName) {
743+
return null;
744+
}
745+
746+
@Override
747+
public JsonNode path(int index) {
748+
return _delegate.path(index);
749+
}
750+
751+
@Override
752+
protected JsonNode _at(JsonPointer ptr) {
753+
return null;
754+
}
755+
756+
@Override
757+
public JsonNodeType getNodeType() {
758+
return JsonNodeType.ARRAY;
759+
}
760+
761+
@Override
762+
public String asText() {
763+
return "";
764+
}
765+
766+
@Override
767+
public JsonNode findValue(String fieldName) {
768+
return null;
769+
}
770+
771+
@Override
772+
public JsonNode findParent(String fieldName) {
773+
return null;
774+
}
775+
776+
@Override
777+
public List<JsonNode> findValues(String fieldName, List<JsonNode> foundSoFar) {
778+
return foundSoFar;
779+
}
780+
781+
@Override
782+
public List<String> findValuesAsText(String fieldName, List<String> foundSoFar) {
783+
return foundSoFar;
784+
}
785+
786+
@Override
787+
public List<JsonNode> findParents(String fieldName, List<JsonNode> foundSoFar) {
788+
return foundSoFar;
789+
}
790+
791+
@Override
792+
public boolean equals(Object o) {
793+
if (o == this) {
794+
return true;
795+
}
796+
if (!(o instanceof DelegatingArrayNode)) {
797+
return false;
798+
}
799+
DelegatingArrayNode other = (DelegatingArrayNode) o;
800+
return this._delegate.equals(other._delegate);
801+
}
802+
803+
@Override
804+
public int hashCode() {
805+
return _delegate.hashCode();
806+
}
807+
}
535808
}

0 commit comments

Comments
 (0)