BAEL-5115 Deduction-Based Polymorphism in Jackson 2.12 (#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
This commit is contained in:
Iulian Manda 2022-04-17 14:16:25 +03:00 committed by GitHub
parent 2d672af774
commit de77319b35
10 changed files with 249 additions and 0 deletions

View File

@ -0,0 +1,12 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
@JsonTypeInfo(use = Id.DEDUCTION)
@JsonSubTypes({ @Type(ImperialSpy.class), @Type(King.class), @Type(Knight.class) })
public interface Character {
}

View File

@ -0,0 +1,14 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
public class ControlledCharacter {
private Character character;
public Character getCharacter() {
return character;
}
public void setCharacter(Character character) {
this.character = character;
}
}

View File

@ -0,0 +1,5 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
public class ImperialSpy implements Character {
}

View File

@ -0,0 +1,14 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
public class King extends NamedCharacter {
private String land;
public String getLand() {
return land;
}
public void setLand(String land) {
this.land = land;
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
public class Knight extends NamedCharacter {
private String weapon;
public String getWeapon() {
return weapon;
}
public void setWeapon(String weapon) {
this.weapon = weapon;
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
public class NamedCharacter implements Character {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,33 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
import static com.baeldung.jackson.deductionbasedpolymorphism.JsonStringFormatterUtil.formatJson;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
class CaseInsensitiveInferenceUnitTest {
private final ObjectMapper objectMapper = JsonMapper.builder()
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
.build();
@Test
void givenACaseInsensitiveKnight_whenMapping_thenExpectKnight() throws Exception {
String knightJson = formatJson("{'NaMe':'Ostrava, of Boletaria', 'WeaPON':'Rune Sword'}");
Character character = objectMapper.readValue(knightJson, Character.class);
assertTrue(character instanceof Knight);
assertSame(character.getClass(), Knight.class);
Knight knight = (Knight) character;
assertEquals("Ostrava, of Boletaria", knight.getName());
assertEquals("Rune Sword", knight.getWeapon());
}
}

View File

@ -0,0 +1,73 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
import static com.baeldung.jackson.deductionbasedpolymorphism.JsonStringFormatterUtil.formatJson;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
class ContainedInferenceUnitTest {
private final ObjectMapper objectMapper = JsonMapper.builder()
.build();
@Test
void givenAKnightControlledCharacter_whenMapping_thenExpectAControlledCharacterWithKnight() throws Exception {
String controlledCharacterJson = formatJson("{'character': {'name': 'Ostrava, of Boletaria', 'weapon': 'Rune Sword'}}");
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
Character character = controlledCharacter.getCharacter();
assertTrue(character instanceof Knight);
assertSame(character.getClass(), Knight.class);
Knight knight = (Knight) character;
assertEquals("Ostrava, of Boletaria", knight.getName());
assertEquals("Rune Sword", knight.getWeapon());
}
@Test
void givenAKingControlledCharacter_whenMapping_thenExpectAControlledCharacterWithKing() throws Exception {
String controlledCharacterJson = formatJson("{'character': {'name': 'King Allant', 'land': 'Boletaria'}}");
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
Character character = controlledCharacter.getCharacter();
assertTrue(character instanceof King);
assertSame(character.getClass(), King.class);
King king = (King) character;
assertEquals("King Allant", king.getName());
assertEquals("Boletaria", king.getLand());
}
@Test
void givenAnEmptySubtype_whenMapping_thenExpectImperialSpy() throws Exception {
String controlledCharacterJson = formatJson("{'character': {}}");
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
assertTrue(controlledCharacter.getCharacter() instanceof ImperialSpy);
}
@Test
void givenANullCharacter_whenMapping_thenExpectNullCharacter() throws Exception {
String controlledCharacterJson = formatJson("{'character': null}");
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
assertNull(controlledCharacter.getCharacter());
}
@Test
void givenAAnAbsentCharacter_whenMapping_thenExpectNullCharacter() throws Exception {
String controlledCharacterJson = formatJson("{}");
ControlledCharacter controlledCharacter = objectMapper.readValue(controlledCharacterJson, ControlledCharacter.class);
assertNull(controlledCharacter.getCharacter());
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
public class JsonStringFormatterUtil {
public static String formatJson(String input) {
return input.replaceAll("'", "\"");
}
}

View File

@ -0,0 +1,61 @@
package com.baeldung.jackson.deductionbasedpolymorphism;
import static com.baeldung.jackson.deductionbasedpolymorphism.JsonStringFormatterUtil.formatJson;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
class SimpleInferenceUnitTest {
private final ObjectMapper objectMapper = JsonMapper.builder()
.build();
@Test
void givenAKnight_whenMapping_thenExpectAKnightType() throws Exception {
String knightJson = formatJson("{'name':'Ostrava, of Boletaria', 'weapon':'Rune Sword'}");
Character character = objectMapper.readValue(knightJson, Character.class);
assertTrue(character instanceof Knight);
assertSame(character.getClass(), Knight.class);
Knight king = (Knight) character;
assertEquals("Ostrava, of Boletaria", king.getName());
assertEquals("Rune Sword", king.getWeapon());
}
@Test
void givenAKing_whenMapping_thenExpectAKingType() throws Exception {
String kingJson = formatJson("{'name':'Old King Allant', 'land':'Boletaria'}");
Character character = objectMapper.readValue(kingJson, Character.class);
assertTrue(character instanceof King);
assertSame(character.getClass(), King.class);
King king = (King) character;
assertEquals("Old King Allant", king.getName());
assertEquals("Boletaria", king.getLand());
}
@Test
void givenAnEmptyObject_whenMapping_thenExpectAnImperialSpy() throws Exception {
String imperialSpyJson = "{}";
Character character = objectMapper.readValue(imperialSpyJson, Character.class);
assertTrue(character instanceof ImperialSpy);
}
@Test
void givenANullObject_whenMapping_thenExpectANullObject() throws Exception {
Character character = objectMapper.readValue("null", Character.class);
assertNull(character);
}
}