Skip to content

Commit 68ef028

Browse files
authored
Allow custom JsonNode implementations (#3701)
1 parent dd733c4 commit 68ef028

File tree

2 files changed

+267
-1
lines changed

2 files changed

+267
-1
lines changed

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

+1-1
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

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

0 commit comments

Comments
 (0)