Skip to content

Commit 659f739

Browse files
authored
BAEL-5115 Deduction-Based Polymorphism in Jackson 2.12 (eugenp#11732)
* BAEL-5115 Deduction-Based Polymorphism in Jackson 2.12 * Fix pmd * Code review changes * Improvements * Code review * Code review * fix typo * Rename package * Apply formatter * Add old deduction * revert
1 parent edd7b4d commit 659f739

10 files changed

Lines changed: 249 additions & 0 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
import com.fasterxml.jackson.annotation.JsonSubTypes;
4+
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
5+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
6+
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
7+
8+
@JsonTypeInfo(use = Id.DEDUCTION)
9+
@JsonSubTypes({ @Type(ImperialSpy.class), @Type(King.class), @Type(Knight.class) })
10+
public interface Character {
11+
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
public class ControlledCharacter {
4+
5+
private Character character;
6+
7+
public Character getCharacter() {
8+
return character;
9+
}
10+
11+
public void setCharacter(Character character) {
12+
this.character = character;
13+
}
14+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
public class ImperialSpy implements Character {
4+
5+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
public class King extends NamedCharacter {
4+
5+
private String land;
6+
7+
public String getLand() {
8+
return land;
9+
}
10+
11+
public void setLand(String land) {
12+
this.land = land;
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
public class Knight extends NamedCharacter {
4+
5+
private String weapon;
6+
7+
public String getWeapon() {
8+
return weapon;
9+
}
10+
11+
public void setWeapon(String weapon) {
12+
this.weapon = weapon;
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
public class NamedCharacter implements Character {
4+
5+
private String name;
6+
7+
public String getName() {
8+
return name;
9+
}
10+
11+
public void setName(String name) {
12+
this.name = name;
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
import static com.baeldung.jackson.deductionbasedpolymorphism.JsonStringFormatterUtil.formatJson;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertSame;
6+
import static org.junit.jupiter.api.Assertions.assertTrue;
7+
8+
import org.junit.jupiter.api.Test;
9+
10+
import com.fasterxml.jackson.databind.MapperFeature;
11+
import com.fasterxml.jackson.databind.ObjectMapper;
12+
import com.fasterxml.jackson.databind.json.JsonMapper;
13+
14+
class CaseInsensitiveInferenceUnitTest {
15+
16+
private final ObjectMapper objectMapper = JsonMapper.builder()
17+
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
18+
.build();
19+
20+
@Test
21+
void givenACaseInsensitiveKnight_whenMapping_thenExpectKnight() throws Exception {
22+
String knightJson = formatJson("{'NaMe':'Ostrava, of Boletaria', 'WeaPON':'Rune Sword'}");
23+
24+
Character character = objectMapper.readValue(knightJson, Character.class);
25+
26+
assertTrue(character instanceof Knight);
27+
assertSame(character.getClass(), Knight.class);
28+
Knight knight = (Knight) character;
29+
assertEquals("Ostrava, of Boletaria", knight.getName());
30+
assertEquals("Rune Sword", knight.getWeapon());
31+
}
32+
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
import static com.baeldung.jackson.deductionbasedpolymorphism.JsonStringFormatterUtil.formatJson;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertNull;
6+
import static org.junit.jupiter.api.Assertions.assertSame;
7+
import static org.junit.jupiter.api.Assertions.assertTrue;
8+
9+
import org.junit.jupiter.api.Test;
10+
11+
import com.fasterxml.jackson.databind.ObjectMapper;
12+
import com.fasterxml.jackson.databind.json.JsonMapper;
13+
14+
class ContainedInferenceUnitTest {
15+
16+
private final ObjectMapper objectMapper = JsonMapper.builder()
17+
.build();
18+
19+
@Test
20+
void givenAKnightControlledCharacter_whenMapping_thenExpectAControlledCharacterWithKnight() throws Exception {
21+
String controlledCharacterJson = formatJson("{'character': {'name': 'Ostrava, of Boletaria', 'weapon': 'Rune Sword'}}");
22+
23+
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
24+
Character character = controlledCharacter.getCharacter();
25+
26+
assertTrue(character instanceof Knight);
27+
assertSame(character.getClass(), Knight.class);
28+
Knight knight = (Knight) character;
29+
assertEquals("Ostrava, of Boletaria", knight.getName());
30+
assertEquals("Rune Sword", knight.getWeapon());
31+
}
32+
33+
@Test
34+
void givenAKingControlledCharacter_whenMapping_thenExpectAControlledCharacterWithKing() throws Exception {
35+
String controlledCharacterJson = formatJson("{'character': {'name': 'King Allant', 'land': 'Boletaria'}}");
36+
37+
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
38+
Character character = controlledCharacter.getCharacter();
39+
40+
assertTrue(character instanceof King);
41+
assertSame(character.getClass(), King.class);
42+
King king = (King) character;
43+
assertEquals("King Allant", king.getName());
44+
assertEquals("Boletaria", king.getLand());
45+
}
46+
47+
@Test
48+
void givenAnEmptySubtype_whenMapping_thenExpectImperialSpy() throws Exception {
49+
String controlledCharacterJson = formatJson("{'character': {}}");
50+
51+
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
52+
53+
assertTrue(controlledCharacter.getCharacter() instanceof ImperialSpy);
54+
}
55+
56+
@Test
57+
void givenANullCharacter_whenMapping_thenExpectNullCharacter() throws Exception {
58+
String controlledCharacterJson = formatJson("{'character': null}");
59+
60+
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
61+
62+
assertNull(controlledCharacter.getCharacter());
63+
}
64+
65+
@Test
66+
void givenAAnAbsentCharacter_whenMapping_thenExpectNullCharacter() throws Exception {
67+
String controlledCharacterJson = formatJson("{}");
68+
69+
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
70+
71+
assertNull(controlledCharacter.getCharacter());
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
public class JsonStringFormatterUtil {
4+
5+
public static String formatJson(String input) {
6+
return input.replaceAll("'", "\"");
7+
}
8+
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.baeldung.jackson.deductionbasedpolymorphism;
2+
3+
import static com.baeldung.jackson.deductionbasedpolymorphism.JsonStringFormatterUtil.formatJson;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertNull;
6+
import static org.junit.jupiter.api.Assertions.assertSame;
7+
import static org.junit.jupiter.api.Assertions.assertTrue;
8+
9+
import org.junit.jupiter.api.Test;
10+
11+
import com.fasterxml.jackson.databind.ObjectMapper;
12+
import com.fasterxml.jackson.databind.json.JsonMapper;
13+
14+
class SimpleInferenceUnitTest {
15+
16+
private final ObjectMapper objectMapper = JsonMapper.builder()
17+
.build();
18+
19+
@Test
20+
void givenAKnight_whenMapping_thenExpectAKnightType() throws Exception {
21+
String knightJson = formatJson("{'name':'Ostrava, of Boletaria', 'weapon':'Rune Sword'}");
22+
23+
Character character = objectMapper.readValue(knightJson, Character.class);
24+
25+
assertTrue(character instanceof Knight);
26+
assertSame(character.getClass(), Knight.class);
27+
Knight king = (Knight) character;
28+
assertEquals("Ostrava, of Boletaria", king.getName());
29+
assertEquals("Rune Sword", king.getWeapon());
30+
}
31+
32+
@Test
33+
void givenAKing_whenMapping_thenExpectAKingType() throws Exception {
34+
String kingJson = formatJson("{'name':'Old King Allant', 'land':'Boletaria'}");
35+
36+
Character character = objectMapper.readValue(kingJson, Character.class);
37+
38+
assertTrue(character instanceof King);
39+
assertSame(character.getClass(), King.class);
40+
King king = (King) character;
41+
assertEquals("Old King Allant", king.getName());
42+
assertEquals("Boletaria", king.getLand());
43+
}
44+
45+
@Test
46+
void givenAnEmptyObject_whenMapping_thenExpectAnImperialSpy() throws Exception {
47+
String imperialSpyJson = "{}";
48+
49+
Character character = objectMapper.readValue(imperialSpyJson, Character.class);
50+
51+
assertTrue(character instanceof ImperialSpy);
52+
}
53+
54+
@Test
55+
void givenANullObject_whenMapping_thenExpectANullObject() throws Exception {
56+
Character character = objectMapper.readValue("null", Character.class);
57+
58+
assertNull(character);
59+
}
60+
61+
}

0 commit comments

Comments
 (0)