CyclicTypesDeserTest.java
package com.fasterxml.jackson.databind.deser;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import static org.junit.jupiter.api.Assertions.*;
import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.*;
/**
* Simple unit tests to verify that it is possible to handle
* potentially cyclic structures, as long as object graph itself
* is not cyclic. This is the case for directed hierarchies like
* trees and DAGs.
*/
public class CyclicTypesDeserTest
{
static class Bean
{
Bean _next;
String _name;
public Bean() { }
public void setNext(Bean b) { _next = b; }
public void setName(String n) { _name = n; }
}
static class LinkA {
public LinkB next;
}
static class LinkB {
protected LinkA a;
public void setA(LinkA a) { this.a = a; }
public LinkA getA() { return a; }
}
static class GenericLink<T> {
public GenericLink<T> next;
}
static class StringLink extends GenericLink<String> {
}
@JsonPropertyOrder({ "id", "parent" })
static class Selfie405 {
public int id;
@JsonIgnoreProperties({ "parent" })
public Selfie405 parent;
public Selfie405(int id) { this.id = id; }
}
/*
/**********************************************************
/* Unit tests
/**********************************************************
*/
private final ObjectMapper MAPPER = newJsonMapper();
@Test
public void testLinked() throws Exception
{
Bean first = MAPPER.readValue
("{\"name\":\"first\", \"next\": { "
+" \"name\":\"last\", \"next\" : null }}",
Bean.class);
assertNotNull(first);
assertEquals("first", first._name);
Bean last = first._next;
assertNotNull(last);
assertEquals("last", last._name);
assertNull(last._next);
}
@Test
public void testLinkedGeneric() throws Exception
{
StringLink link = MAPPER.readValue("{\"next\":null}", StringLink.class);
assertNotNull(link);
assertNull(link.next);
}
@Test
public void testCycleWith2Classes() throws Exception
{
LinkA a = MAPPER.readValue("{\"next\":{\"a\":null}}", LinkA.class);
assertNotNull(a.next);
LinkB b = a.next;
assertNull(b.a);
}
// [Issue#405]: Should be possible to ignore cyclic ref
@Test
public void testIgnoredCycle() throws Exception
{
Selfie405 self1 = new Selfie405(1);
self1.parent = self1;
// First: exception with default settings:
assertTrue(MAPPER.isEnabled(SerializationFeature.FAIL_ON_SELF_REFERENCES));
try {
MAPPER.writeValueAsString(self1);
fail("Should fail with direct self-ref");
} catch (InvalidDefinitionException e) {
verifyException(e, "Direct self-reference");
}
ObjectWriter w = MAPPER.writer()
.without(SerializationFeature.FAIL_ON_SELF_REFERENCES);
String json = w.writeValueAsString(self1);
assertNotNull(json);
assertEquals(a2q("{'id':1,'parent':{'id':1}}"), json);
}
}