fix type conversion

dev
Exlll 8 years ago
parent 71f342783b
commit a61363aefd

@ -1,5 +1,5 @@
name: ConfigLib
author: Exlll
version: 1.3.0
version: 1.3.1
main: de.exlll.configlib.ConfigLib

@ -1,5 +1,5 @@
name: ConfigLib
author: Exlll
version: 1.3.0
version: 1.3.1
main: de.exlll.configlib.ConfigLib

@ -80,6 +80,7 @@ enum Reflect {
static void setValue(Field field, Object instance, Object value) {
try {
field.setAccessible(true);
value = TypeConverter.convertValue(field.getType(), value);
field.set(instance, value);
} catch (IllegalAccessException e) {
/* This exception is never thrown because we filter

@ -0,0 +1,85 @@
package de.exlll.configlib;
import java.util.Objects;
enum TypeConverter {
;
static Object convertValue(Class<?> target, Object value) {
Objects.requireNonNull(target);
Objects.requireNonNull(value);
if (target == value.getClass()) {
return value;
}
if (value instanceof Number) {
return convertNumber(target, (Number) value);
}
if (value instanceof String) {
return convertString((String) value);
}
return value;
}
static Character convertString(String s) {
int len = s.length();
if (len != 1) {
String msg = "String '" + s + "' cannot be converted to a character." +
" Length of s: " + len + " Required length: 1";
throw new IllegalArgumentException(msg);
}
return s.charAt(0);
}
static Number convertNumber(Class<?> targetType, Number number) {
if (isByteClass(targetType)) {
return number.byteValue();
} else if (isShortClass(targetType)) {
return number.shortValue();
} else if (isIntegerClass(targetType)) {
return number.intValue();
} else if (isLongClass(targetType)) {
return number.longValue();
} else if (isFloatClass(targetType)) {
return number.floatValue();
} else if (isDoubleClass(targetType)) {
return number.doubleValue();
} else {
String msg = "Number cannot be converted to target type " +
"'" + targetType + "'";
throw new IllegalArgumentException(msg);
}
}
static boolean isBooleanClass(Class<?> cls) {
return (cls == Boolean.class) || (cls == Boolean.TYPE);
}
static boolean isByteClass(Class<?> cls) {
return (cls == Byte.class) || (cls == Byte.TYPE);
}
static boolean isShortClass(Class<?> cls) {
return (cls == Short.class) || (cls == Short.TYPE);
}
static boolean isIntegerClass(Class<?> cls) {
return (cls == Integer.class) || (cls == Integer.TYPE);
}
static boolean isLongClass(Class<?> cls) {
return (cls == Long.class) || (cls == Long.TYPE);
}
static boolean isFloatClass(Class<?> cls) {
return (cls == Float.class) || (cls == Float.TYPE);
}
static boolean isDoubleClass(Class<?> cls) {
return (cls == Double.class) || (cls == Double.TYPE);
}
static boolean isCharacterClass(Class<?> cls) {
return (cls == Character.class) || (cls == Character.TYPE);
}
}

@ -15,6 +15,7 @@ import org.junit.runners.Suite;
FieldMapperTest.class,
FilteredFieldsTest.class,
ReflectTest.class,
TypeConverterTest.class,
YamlSerializerTest.class
})
public class ConfigLibTestSuite {

@ -1,6 +1,9 @@
package de.exlll.configlib;
import com.google.common.jimfs.Jimfs;
import de.exlll.configlib.classes.DefaultTypeClass;
import de.exlll.configlib.classes.NonDefaultTypeClass;
import de.exlll.configlib.classes.SimpleTypesClass;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -13,7 +16,6 @@ import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
public class ConfigurationTest {
private FileSystem fileSystem;
private Path configPath;
@ -46,4 +48,25 @@ public class ConfigurationTest {
assertThat(Files.exists(configPath), is(true));
assertThat(ConfigReader.read(configPath), is(TestConfiguration.CONFIG_AS_TEXT));
}
@Test
public void simpleTypesConfigSavesAndLoads() throws Exception {
Configuration cfg = new SimpleTypesClass(configPath);
cfg.save();
cfg.load();
}
@Test
public void defaultTypesConfigSavesAndLoads() throws Exception {
Configuration cfg = new DefaultTypeClass(configPath);
cfg.save();
cfg.load();
}
@Test
public void nonDefaultConfigSavesAndLoads() throws Exception {
Configuration cfg = new NonDefaultTypeClass(configPath);
cfg.save();
cfg.load();
}
}

@ -5,6 +5,8 @@ import de.exlll.configlib.classes.NonDefaultTypeClass;
import org.junit.Test;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@ -14,9 +16,11 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
public class FieldMapperTest {
private final Path path = Paths.get("a");
@Test
public void toSerializableObjectReturnsObjectForDefaultTypes() throws Exception {
DefaultTypeClass instance = new DefaultTypeClass();
DefaultTypeClass instance = new DefaultTypeClass(path);
for (Field f : DefaultTypeClass.class.getDeclaredFields()) {
Object value = Reflect.getValue(f, instance);
assertThat(FieldMapper.toSerializableObject(value), sameInstance(value));
@ -25,7 +29,7 @@ public class FieldMapperTest {
@Test
public void toSerializableObjectReturnsMapForNonDefaultTypes() throws Exception {
DefaultTypeClass instance = new DefaultTypeClass();
DefaultTypeClass instance = new DefaultTypeClass(path);
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) FieldMapper.toSerializableObject(instance);
@ -41,7 +45,7 @@ public class FieldMapperTest {
@Test
public void fromSerializedObjectIgnoresNullValues() throws Exception {
DefaultTypeClass instance = new DefaultTypeClass();
DefaultTypeClass instance = new DefaultTypeClass(path);
for (Field field : DefaultTypeClass.class.getDeclaredFields()) {
Object currentValue = Reflect.getValue(field, instance);
@ -58,7 +62,7 @@ public class FieldMapperTest {
@Test
public void fromSerializedObjectSetsValueIfDefaultType() throws Exception {
DefaultTypeClass instance = new DefaultTypeClass();
DefaultTypeClass instance = new DefaultTypeClass(path);
Map<String, Object> map = DefaultTypeClass.newValues();
for (Field field : DefaultTypeClass.class.getDeclaredFields()) {
@ -77,7 +81,7 @@ public class FieldMapperTest {
@Test
public void fromSerializedObjectUpdatesValueIfNotDefaultType() throws Exception {
NonDefaultTypeClass instance = new NonDefaultTypeClass();
NonDefaultTypeClass instance = new NonDefaultTypeClass(path);
Field field = NonDefaultTypeClass.class.getDeclaredField("defaultTypeClass");
Map<String, Object> map = DefaultTypeClass.newValues();

@ -0,0 +1,167 @@
package de.exlll.configlib;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
public class TypeConverterTest {
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void convertValueReturnsSameInstanceIfNoConversion() throws Exception {
Map<?, ?> map = new HashMap<>();
assertThat(TypeConverter.convertValue(Map.class, map), sameInstance(map));
}
@Test
public void convertValueConvertsString() throws Exception {
assertThat(TypeConverter.convertString("z"), is('z'));
}
@Test
public void convertValueConvertsNumber() throws Exception {
Integer i = 10;
Object o = TypeConverter.convertValue(Short.class, i);
assertThat(o, instanceOf(Short.class));
assertThat(o, is((short) 10));
}
@Test
public void convertValueReturnsInstanceIfTypesMatch() throws Exception {
Object o = new Object();
Object converted = TypeConverter.convertValue(Object.class, o);
assertThat(o, sameInstance(converted));
}
@Test
public void convertValueRequiresNonNullClass() throws Exception {
exception.expect(NullPointerException.class);
TypeConverter.convertValue(Object.class, null);
}
@Test
public void convertValueRequiresNonNullValue() throws Exception {
exception.expect(NullPointerException.class);
TypeConverter.convertValue(null, new Object());
}
@Test
public void convertStringThrowsExceptionIfStringLength0() throws Exception {
exception.expect(IllegalArgumentException.class);
TypeConverter.convertString("");
}
@Test
public void convertStringThrowsExceptionIfStringLengthBiggerThan1() throws Exception {
exception.expect(IllegalArgumentException.class);
TypeConverter.convertString("ab");
}
@Test
public void convertStringReturnsCharacter() throws Exception {
String s = "z";
char c = 'z';
Character character = TypeConverter.convertString(s);
assertThat(character, is(c));
}
@Test
public void convertNumberThrowsExceptionIfUnknownType() throws Exception {
exception.expect(IllegalArgumentException.class);
exception.expectMessage("Number cannot be converted to target type " +
"'class java.lang.Object'");
TypeConverter.convertNumber(Object.class, 1);
}
@Test
public void convertNumberReturnsConvertedNumber() throws Exception {
Number[] numbers = {(byte) 1, (short) 2, 3, 4L, 5.0F, 6.0};
Class<?>[] numClasses = {
Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class
};
for (Class<?> numClass : numClasses) {
for (Number number : numbers) {
Number n = TypeConverter.convertNumber(numClass, number);
assertThat(n, instanceOf(numClass));
// this is only true because we use values that
// don't cause an overflow
assertThat(n.doubleValue(), is(number.doubleValue()));
}
}
int i = Short.MAX_VALUE + 1;
Number n = TypeConverter.convertNumber(Short.class, i);
assertThat(n, is(Short.MIN_VALUE));
}
@Test
public void isBooleanClass() throws Exception {
assertThat(TypeConverter.isBooleanClass(Boolean.class), is(true));
assertThat(TypeConverter.isBooleanClass(boolean.class), is(true));
assertThat(TypeConverter.isBooleanClass(Object.class), is(false));
}
@Test
public void isByteClass() throws Exception {
assertThat(TypeConverter.isByteClass(Byte.class), is(true));
assertThat(TypeConverter.isByteClass(byte.class), is(true));
assertThat(TypeConverter.isByteClass(Object.class), is(false));
}
@Test
public void isShortClass() throws Exception {
assertThat(TypeConverter.isShortClass(Short.class), is(true));
assertThat(TypeConverter.isShortClass(short.class), is(true));
assertThat(TypeConverter.isShortClass(Object.class), is(false));
}
@Test
public void isIntegerClass() throws Exception {
assertThat(TypeConverter.isIntegerClass(Integer.class), is(true));
assertThat(TypeConverter.isIntegerClass(int.class), is(true));
assertThat(TypeConverter.isIntegerClass(Object.class), is(false));
}
@Test
public void isLongClass() throws Exception {
assertThat(TypeConverter.isLongClass(Long.class), is(true));
assertThat(TypeConverter.isLongClass(long.class), is(true));
assertThat(TypeConverter.isLongClass(Object.class), is(false));
}
@Test
public void isFloatClass() throws Exception {
assertThat(TypeConverter.isFloatClass(Float.class), is(true));
assertThat(TypeConverter.isFloatClass(float.class), is(true));
assertThat(TypeConverter.isFloatClass(Object.class), is(false));
}
@Test
public void isDoubleClass() throws Exception {
assertThat(TypeConverter.isDoubleClass(Double.class), is(true));
assertThat(TypeConverter.isDoubleClass(double.class), is(true));
assertThat(TypeConverter.isDoubleClass(Object.class), is(false));
}
@Test
public void isCharacterClass() throws Exception {
assertThat(TypeConverter.isCharacterClass(Character.class), is(true));
assertThat(TypeConverter.isCharacterClass(char.class), is(true));
assertThat(TypeConverter.isCharacterClass(Object.class), is(false));
}
}

@ -1,8 +1,11 @@
package de.exlll.configlib.classes;
import de.exlll.configlib.Configuration;
import java.nio.file.Path;
import java.util.*;
public class DefaultTypeClass {
public class DefaultTypeClass extends Configuration {
private boolean bool = true;
private char c = 'c';
private byte b = 1;
@ -24,7 +27,8 @@ public class DefaultTypeClass {
private Set<String> set = new HashSet<>();
private Map<String, String> map = new HashMap<>();
public DefaultTypeClass() {
public DefaultTypeClass(Path path) {
super(path);
list.add("a");
set.add("b");
map.put("c", "d");

@ -1,5 +1,14 @@
package de.exlll.configlib.classes;
public class NonDefaultTypeClass {
public DefaultTypeClass defaultTypeClass = new DefaultTypeClass();
import de.exlll.configlib.Configuration;
import java.nio.file.Path;
public class NonDefaultTypeClass extends Configuration {
public DefaultTypeClass defaultTypeClass;
public NonDefaultTypeClass(Path configPath) {
super(configPath);
this.defaultTypeClass = new DefaultTypeClass(configPath);
}
}

@ -1,6 +1,10 @@
package de.exlll.configlib.classes;
public class SimpleTypesClass {
import de.exlll.configlib.Configuration;
import java.nio.file.Path;
public class SimpleTypesClass extends Configuration {
private boolean bool = true;
private char c = 'c';
private byte b = 1;
@ -18,4 +22,8 @@ public class SimpleTypesClass {
private Float fObject = 5.0f;
private Double dObject = 6.0;
private String string = "string";
public SimpleTypesClass(Path configPath) {
super(configPath);
}
}

@ -135,14 +135,14 @@ public class ExamplePlugin extends JavaPlugin {
<dependency>
<groupId>de.exlll</groupId>
<artifactId>configlib-bukkit</artifactId>
<version>1.3.0</version>
<version>1.3.1</version>
</dependency>
<!-- for Bungee plugins -->
<dependency>
<groupId>de.exlll</groupId>
<artifactId>configlib-bungee</artifactId>
<version>1.3.0</version>
<version>1.3.1</version>
</dependency>
```
#### Gradle
@ -154,10 +154,10 @@ repositories {
}
dependencies {
// for Bukkit plugins
compile group: 'de.exlll', name: 'configlib-bukkit', version: '1.3.0'
compile group: 'de.exlll', name: 'configlib-bukkit', version: '1.3.1'
// for Bungee plugins
compile group: 'de.exlll', name: 'configlib-bungee', version: '1.3.0'
compile group: 'de.exlll', name: 'configlib-bungee', version: '1.3.1'
}
```
Additionally, you either have to import the Bukkit or BungeeCord API

@ -1,6 +1,6 @@
allprojects {
group 'de.exlll'
version '1.3.0'
version '1.3.1'
}
subprojects {
apply plugin: 'java'

Loading…
Cancel
Save