Add tests for polymorphic type handling

This commit is contained in:
Nemanja Zbiljić 2017-10-15 13:27:17 +02:00
parent c96977bb14
commit c39ae8c7ca
12 changed files with 940 additions and 0 deletions

View File

@ -0,0 +1,45 @@
package beanconfig.polymorphic;
import com.typesafe.config.ConfigSubTypes;
import com.typesafe.config.ConfigSubTypes.Type;
import com.typesafe.config.ConfigTypeInfo;
import java.util.List;
public class PolymorphicWithDefaultImpl {
@ConfigTypeInfo(defaultImpl = LegacyInter.class)
@ConfigSubTypes(value = {
@Type(value = MyInter.class, name = "mine")
})
public interface Inter {}
public static class MyInter implements Inter {
private List<String> blah;
public List<String> getBlah() {
return blah;
}
public void setBlah(List<String> blah) {
this.blah = blah;
}
}
public static class LegacyInter extends MyInter {
}
/*
* can use non-deprecated value for the same
*/
@ConfigTypeInfo(defaultImpl = Void.class)
public static class DefaultWithVoidAsDefault {}
/*
* one with no defaultImpl nor listed subtypes
*/
@ConfigTypeInfo
public abstract static class MysteryPolymorphic {}
}

View File

@ -0,0 +1,65 @@
package beanconfig.polymorphic;
import beanconfig.polymorphic.PolymorphicWithDefaultImpl.DefaultWithVoidAsDefault;
import beanconfig.polymorphic.PolymorphicWithDefaultImpl.Inter;
import beanconfig.polymorphic.PolymorphicWithDefaultImpl.MysteryPolymorphic;
public class PolymorphicWithDefaultImplConfigs {
public static class InnerConfig {
private Inter object;
private Inter array;
public Inter getObject() {
return object;
}
public void setObject(Inter object) {
this.object = object;
}
public Inter getArray() {
return array;
}
public void setArray(Inter array) {
this.array = array;
}
}
public static class DefaultWithVoidAsDefaultConfig {
private DefaultWithVoidAsDefault defaultAsVoid1;
private DefaultWithVoidAsDefault defaultAsVoid2;
public DefaultWithVoidAsDefault getDefaultAsVoid1() {
return defaultAsVoid1;
}
public void setDefaultAsVoid1(DefaultWithVoidAsDefault defaultAsVoid1) {
this.defaultAsVoid1 = defaultAsVoid1;
}
public DefaultWithVoidAsDefault getDefaultAsVoid2() {
return defaultAsVoid2;
}
public void setDefaultAsVoid2(DefaultWithVoidAsDefault defaultAsVoid2) {
this.defaultAsVoid2 = defaultAsVoid2;
}
}
public static class MysteryPolymorphicConfig {
private MysteryPolymorphic badType;
public MysteryPolymorphic getBadType() {
return badType;
}
public void setBadType(MysteryPolymorphic badType) {
this.badType = badType;
}
}
}

View File

@ -0,0 +1,143 @@
package beanconfig.polymorphic;
import com.typesafe.config.ConfigSubTypes;
import com.typesafe.config.ConfigSubTypes.Type;
import com.typesafe.config.ConfigTypeInfo;
import com.typesafe.config.ConfigTypeName;
import com.typesafe.config.Optional;
public class Subtypes {
@ConfigTypeInfo
@ConfigSubTypes({
@Type(value = SubB.class),
@Type(value = SubC.class),
@Type(value = SubD.class)
})
public static abstract class SuperType {
}
@ConfigTypeName("TypeB")
public static class SubB extends SuperType {
private int b = 1;
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}
public static class SubC extends SuperType {
private int c = 2;
public int getC() {
return c;
}
public void setC(int c) {
this.c = c;
}
}
public static class SubD extends SuperType {
private int d;
public int getD() {
return d;
}
public void setD(int d) {
this.d = d;
}
}
@ConfigTypeInfo(defaultImpl = DefaultImpl.class)
public static abstract class SuperTypeWithDefault {}
public static class DefaultImpl extends SuperTypeWithDefault {
@Optional
private int a;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
@ConfigTypeInfo
@ConfigSubTypes({
@Type(ImplX.class),
@Type(ImplY.class)
})
public static abstract class BaseX {}
@ConfigTypeName("x")
public static class ImplX extends BaseX {
private int x;
public ImplX() {
}
public ImplX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
}
@ConfigTypeName("y")
public static class ImplY extends BaseX {
private int y;
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
public static class AtomicWrapper {
private BaseX value;
public AtomicWrapper() {
}
public AtomicWrapper(int x) {
value = new ImplX(x);
}
public BaseX getDirectValue() {
return value;
}
public int getValue() {
return ((ImplX) value).getX();
}
public void setValue(int value) {
this.value = new ImplX(value);
}
}
}

View File

@ -0,0 +1,75 @@
package beanconfig.polymorphic;
import beanconfig.polymorphic.Subtypes.AtomicWrapper;
import beanconfig.polymorphic.Subtypes.SuperType;
import beanconfig.polymorphic.Subtypes.SuperTypeWithDefault;
public class SubtypesConfigs {
public static class SuperTypeConfig {
private SuperType bean1;
private SuperType bean2;
public SuperType getBean1() {
return bean1;
}
public void setBean1(SuperType bean1) {
this.bean1 = bean1;
}
public SuperType getBean2() {
return bean2;
}
public void setBean2(SuperType bean2) {
this.bean2 = bean2;
}
}
public static class DefaultImplConfig {
private SuperTypeWithDefault defaultImpl1;
private SuperTypeWithDefault defaultImpl2;
private SuperTypeWithDefault defaultImpl3;
public SuperTypeWithDefault getDefaultImpl1() {
return defaultImpl1;
}
public void setDefaultImpl1(SuperTypeWithDefault defaultImpl1) {
this.defaultImpl1 = defaultImpl1;
}
public SuperTypeWithDefault getDefaultImpl2() {
return defaultImpl2;
}
public void setDefaultImpl2(SuperTypeWithDefault defaultImpl2) {
this.defaultImpl2 = defaultImpl2;
}
public SuperTypeWithDefault getDefaultImpl3() {
return defaultImpl3;
}
public void setDefaultImpl3(SuperTypeWithDefault defaultImpl3) {
this.defaultImpl3 = defaultImpl3;
}
}
public static class AtomicWrapperConfig {
private AtomicWrapper atomicWrapper;
public AtomicWrapper getAtomicWrapper() {
return atomicWrapper;
}
public void setAtomicWrapper(AtomicWrapper atomicWrapper) {
this.atomicWrapper = atomicWrapper;
}
}
}

View File

@ -0,0 +1,132 @@
package beanconfig.polymorphic;
import com.typesafe.config.ConfigSubTypes;
import com.typesafe.config.ConfigSubTypes.Type;
import com.typesafe.config.ConfigTypeInfo;
import com.typesafe.config.ConfigTypeName;
public class TypeNames {
@ConfigTypeInfo
@ConfigSubTypes({
@Type(value = Dog.class, name = "doggy"),
@Type(Cat.class) /* defaults to "Cat" then */
})
public static class Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@ConfigSubTypes({
@Type(MaineCoon.class),
@Type(Persian.class)
})
public static abstract class Cat extends Animal {
private boolean purrs;
public boolean isPurrs() {
return purrs;
}
public void setPurrs(boolean purrs) {
this.purrs = purrs;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Cat cat = (Cat) o;
return purrs == cat.purrs;
}
@Override
public int hashCode() {
return (purrs ? 1 : 0);
}
}
public static class Dog extends Animal {
private int ageInYears;
public int getAgeInYears() {
return ageInYears;
}
public void setAgeInYears(int ageInYears) {
this.ageInYears = ageInYears;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Dog dog = (Dog) o;
return ageInYears == dog.ageInYears;
}
@Override
public int hashCode() {
return ageInYears;
}
@Override
public String toString() {
return "Dog{" +
"ageInYears=" + ageInYears +
'}';
}
}
/*
* Uses default name ("MaineCoon") since there's no @ConfigTypeName,
* nor did supertype specify name.
*/
public static class MaineCoon extends Cat {
public MaineCoon() {
super();
}
@Override
public String toString() {
return "Cat{" +
"purrs=" + isPurrs() +
'}';
}
}
@ConfigTypeName("persialaisKissa")
public static class Persian extends Cat {
public Persian() {
super();
}
@Override
public String toString() {
return "Cat{" +
"purrs=" + isPurrs() +
'}';
}
}
}

View File

@ -0,0 +1,53 @@
package beanconfig.polymorphic;
import beanconfig.polymorphic.TypeNames.Animal;
import java.util.List;
public class TypeNamesConfigs {
public static class SingleTypeConfig {
private Animal dog;
public Animal getDog() {
return dog;
}
public void setDog(Animal dog) {
this.dog = dog;
}
}
public static class TypeNamesListConfig {
List<Animal> dogs;
List<Animal> cats;
List<Animal> animals;
public List<Animal> getDogs() {
return dogs;
}
public void setDogs(List<Animal> dogs) {
this.dogs = dogs;
}
public List<Animal> getCats() {
return cats;
}
public void setCats(List<Animal> cats) {
this.cats = cats;
}
public List<Animal> getAnimals() {
return animals;
}
public void setAnimals(List<Animal> animals) {
this.animals = animals;
}
}
}

View File

@ -0,0 +1,33 @@
package beanconfig.polymorphic;
import com.typesafe.config.ConfigTypeInfo;
import com.typesafe.config.ConfigTypeName;
public class VisibleTypeId {
@ConfigTypeInfo(visible = true)
@ConfigTypeName("BaseType")
public static class PropertyBean {
private int a = 3;
private String type;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
}

View File

@ -0,0 +1,20 @@
package beanconfig.polymorphic;
import beanconfig.polymorphic.VisibleTypeId.PropertyBean;
public class VisibleTypeIdConfigs {
public static class VisibleTypeConfig {
private PropertyBean bean;
public PropertyBean getBean() {
return bean;
}
public void setBean(PropertyBean bean) {
this.bean = bean;
}
}
}

View File

@ -0,0 +1,56 @@
package beanconfig.polymorphic;
import com.typesafe.config.ConfigSubTypes;
import com.typesafe.config.ConfigSubTypes.Type;
import com.typesafe.config.ConfigTypeInfo;
public class WithGenerics {
@ConfigTypeInfo(property = "object-type")
@ConfigSubTypes({
@Type(value = Dog.class, name = "doggy")
})
public static abstract class Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class Dog extends Animal {
private int boneCount;
public Dog() {
super();
}
public int getBoneCount() {
return boneCount;
}
public void setBoneCount(int boneCount) {
this.boneCount = boneCount;
}
}
public static class ContainerWithAnimal<T extends Animal> {
private T animal;
public void setAnimal(T animal) {
this.animal = animal;
}
public T getAnimal() {
return animal;
}
}
}

View File

@ -0,0 +1,21 @@
package beanconfig.polymorphic;
import beanconfig.polymorphic.WithGenerics.Animal;
import beanconfig.polymorphic.WithGenerics.ContainerWithAnimal;
public class WithGenericsConfigs {
public static class WrapperWithGenericsConfig {
private ContainerWithAnimal<Animal> wrapperWithDog;
public ContainerWithAnimal<Animal> getWrapperWithDog() {
return wrapperWithDog;
}
public void setWrapperWithDog(ContainerWithAnimal<Animal> wrapperWithDog) {
this.wrapperWithDog = wrapperWithDog;
}
}
}

View File

@ -0,0 +1,108 @@
{
"polymorphicWithDefaultImpl": {
"object": {
"type": "mine"
"blah": ["a", "b", "c"]
}
"array": {
"blah": ["a", "b", "c", "d"]
}
"defaultAsVoid1": {}
"defaultAsVoid2": {
"bogus": 3
}
"badType": {
"whatever": 13
}
}
"subtypes": {
"bean1": {
"type": "TypeB"
"b": 13
}
"bean2": {
"type": "SubD"
"d": -4
}
"defaultImpl1": {
"a": 13
}
"defaultImpl2": {
"a": 14
"type": "foobar"
}
"defaultImpl3": {
"type": "foobar"
}
"atomicWrapper": {
"value": 3
}
}
"typeNames": {
"dog": {
"type": "doggy"
"name": "Smiley"
"ageInYears": 1
}
"dogs": [
{
"type": "doggy"
"name": "Spot"
"ageInYears": 3
}
{
"type": "doggy"
"name": "Odie"
"ageInYears": 7
}
]
"cats": [
{
"type": "MaineCoon"
"name": "Belzebub"
"purrs": true
}
{
"type": "MaineCoon"
"name": "Piru"
"purrs": false
}
{
"type": "persialaisKissa"
"name": "Khomeini"
"purrs": true
}
]
"animals": [
{
"type": "MaineCoon"
"name": "Venla"
"purrs": true
}
{
"type": "doggy"
"name": "Amadeus"
"ageInYears": 13
}
]
}
"visibleTypeId": {
"bean" {
"type": "BaseType"
"a": 3
}
}
"withGenerics": {
"wrapperWithDog": {
"animal": {
"object-type": "doggy"
"name": "Fluffy"
"boneCount": 3
}
}
}
}

View File

@ -0,0 +1,189 @@
package com.typesafe.config.impl
import java.io.{InputStream, InputStreamReader}
import beanconfig.polymorphic.PolymorphicWithDefaultImpl._
import beanconfig.polymorphic.PolymorphicWithDefaultImplConfigs._
import beanconfig.polymorphic.Subtypes._
import beanconfig.polymorphic.SubtypesConfigs._
import beanconfig.polymorphic.TypeNames._
import beanconfig.polymorphic.TypeNamesConfigs._
import beanconfig.polymorphic.VisibleTypeId._
import beanconfig.polymorphic.VisibleTypeIdConfigs._
import beanconfig.polymorphic.WithGenericsConfigs._
import beanconfig.polymorphic.{TypeNames, WithGenerics}
import com.typesafe.config._
import org.junit.Assert._
import org.junit._
import scala.collection.JavaConverters._
class ConfigPolymorphicBeanTest extends TestUtils {
@Test
def testDeserializationWithObject() {
val beanConfig: InnerConfig =
ConfigBeanFactory.create(loadConfig().getConfig("polymorphicWithDefaultImpl"), classOf[InnerConfig])
assertNotNull(beanConfig)
assertTrue(beanConfig.getObject.isInstanceOf[MyInter])
assertFalse(beanConfig.getObject.isInstanceOf[LegacyInter])
assertEquals(List("a", "b", "c").asJava, beanConfig.getObject.asInstanceOf[MyInter].getBlah)
}
@Test
def testDeserializationWithArray() {
val beanConfig: InnerConfig =
ConfigBeanFactory.create(loadConfig().getConfig("polymorphicWithDefaultImpl"), classOf[InnerConfig])
assertNotNull(beanConfig)
assertTrue(beanConfig.getArray.isInstanceOf[LegacyInter])
assertEquals(List("a", "b", "c", "d").asJava, beanConfig.getArray.asInstanceOf[LegacyInter].getBlah)
}
@Test
def testDefaultAsVoid() {
val beanConfig: DefaultWithVoidAsDefaultConfig =
ConfigBeanFactory.create(loadConfig().getConfig("polymorphicWithDefaultImpl"),
classOf[DefaultWithVoidAsDefaultConfig])
assertNotNull(beanConfig)
assertNull(beanConfig.getDefaultAsVoid1)
assertNull(beanConfig.getDefaultAsVoid2)
}
@Test
def testBadTypeAsNull() {
val e = intercept[ConfigException.BadBean] {
ConfigBeanFactory.create(loadConfig().getConfig("polymorphicWithDefaultImpl"), classOf[MysteryPolymorphicConfig])
}
assertTrue("no default implementation", e.getMessage.contains("has no default implementation"))
}
@Test
def testDeserialization() {
val beanConfig: SuperTypeConfig = ConfigBeanFactory.create(loadConfig().getConfig("subtypes"), classOf[SuperTypeConfig])
assertNotNull(beanConfig)
assertTrue(beanConfig.getBean1.isInstanceOf[SubB])
assertEquals(13, beanConfig.getBean1.asInstanceOf[SubB].getB)
assertTrue(beanConfig.getBean2.isInstanceOf[SubD])
assertEquals(-4, beanConfig.getBean2.asInstanceOf[SubD].getD)
}
@Test
def testDefaultImpl() {
val beanConfig: DefaultImplConfig =
ConfigBeanFactory.create(loadConfig().getConfig("subtypes"), classOf[DefaultImplConfig])
assertNotNull(beanConfig)
// first, test with no type information
assertTrue(beanConfig.getDefaultImpl1.isInstanceOf[SuperTypeWithDefault])
assertEquals(13, beanConfig.getDefaultImpl1.asInstanceOf[DefaultImpl].getA)
// and then with unmapped info
assertTrue(beanConfig.getDefaultImpl2.isInstanceOf[SuperTypeWithDefault])
assertEquals(14, beanConfig.getDefaultImpl2.asInstanceOf[DefaultImpl].getA)
assertTrue(beanConfig.getDefaultImpl3.isInstanceOf[SuperTypeWithDefault])
assertEquals(0, beanConfig.getDefaultImpl3.asInstanceOf[DefaultImpl].getA)
}
@Test
def testViaAtomic() {
val beanConfig: AtomicWrapperConfig =
ConfigBeanFactory.create(loadConfig().getConfig("subtypes"), classOf[AtomicWrapperConfig])
assertNotNull(beanConfig)
assertTrue(beanConfig.getAtomicWrapper.getDirectValue.isInstanceOf[ImplX])
assertEquals(3, beanConfig.getAtomicWrapper.getValue)
}
@Test
def testCreateSpecificType() {
val beanConfig: SingleTypeConfig =
ConfigBeanFactory.create(loadConfig().getConfig("typeNames"), classOf[SingleTypeConfig])
assertNotNull(beanConfig)
assertNotNull(beanConfig.getDog)
assertTrue(beanConfig.getDog.isInstanceOf[TypeNames.Dog])
assertEquals("Smiley", beanConfig.getDog.getName)
assertEquals(1, beanConfig.getDog.asInstanceOf[TypeNames.Dog].getAgeInYears)
}
@Test
def testCreateList() {
val beanConfig: TypeNamesListConfig =
ConfigBeanFactory.create(loadConfig().getConfig("typeNames"), classOf[TypeNamesListConfig])
assertNotNull(beanConfig)
assertEquals(2, beanConfig.getDogs.size)
assertEquals(3, beanConfig.getCats.size)
assertEquals(2, beanConfig.getAnimals.size)
val dogsConfigOne = new Dog()
dogsConfigOne.setName("Spot")
dogsConfigOne.setAgeInYears(3)
val dogsConfigTwo = new Dog()
dogsConfigTwo.setName("Odie")
dogsConfigTwo.setAgeInYears(7)
assertEquals(List(dogsConfigOne, dogsConfigTwo).asJava, beanConfig.getDogs)
val catsConfigOne = new MaineCoon()
catsConfigOne.setName("Belzebub")
catsConfigOne.setPurrs(true)
val catsConfigTwo = new MaineCoon()
catsConfigTwo.setName("Piru")
catsConfigTwo.setPurrs(false)
val catsConfigThree = new Persian()
catsConfigThree.setName("Khomeini")
catsConfigThree.setPurrs(true)
assertEquals(List(catsConfigOne, catsConfigTwo, catsConfigThree).asJava, beanConfig.getCats)
val animalsConfigOne = new MaineCoon()
animalsConfigOne.setName("Venla")
animalsConfigOne.setPurrs(true)
val animalsConfigTwo = new Dog()
animalsConfigTwo.setName("Amadeus")
animalsConfigTwo.setAgeInYears(13)
assertEquals(List(animalsConfigOne, animalsConfigTwo).asJava, beanConfig.getAnimals)
}
@Test
def testVisible() {
val beanConfig: VisibleTypeConfig =
ConfigBeanFactory.create(loadConfig().getConfig("visibleTypeId"), classOf[VisibleTypeConfig])
assertNotNull(beanConfig)
assertTrue(beanConfig.getBean.isInstanceOf[PropertyBean])
assertEquals("BaseType", beanConfig.getBean.getType)
assertEquals(3, beanConfig.getBean.getA)
}
@Test
def testWrapperWithGenerics() {
val beanConfig: WrapperWithGenericsConfig =
ConfigBeanFactory.create(loadConfig().getConfig("withGenerics"), classOf[WrapperWithGenericsConfig])
assertNotNull(beanConfig)
assertTrue(beanConfig.getWrapperWithDog.getAnimal.isInstanceOf[WithGenerics.Dog])
assertEquals("Fluffy", beanConfig.getWrapperWithDog.getAnimal.getName)
assertEquals(3, beanConfig.getWrapperWithDog.getAnimal.asInstanceOf[WithGenerics.Dog].getBoneCount)
}
private def loadConfig(): Config = {
val configIs: InputStream = this.getClass().getClassLoader().getResourceAsStream("beanconfig/polymorphic01.conf")
try {
val config: Config = ConfigFactory.parseReader(new InputStreamReader(configIs),
ConfigParseOptions.defaults.setSyntax(ConfigSyntax.CONF)).resolve
config
} finally {
configIs.close()
}
}
}