[configuration] Implemented the StringResolver

This commit is contained in:
Roel Spilker committed 2013-12-21 21:50:12 +01:00
1 parent 43ead7d65f
commit a23f56c21b
4 files changed
+258 -44

No files matched your search

@@ -23,15 +23,85 @@ package lombok.core.configuration;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class ConfigurationDataType {
private static final List<Class<?>> SIMPLE_TYPES = Arrays.<Class<?>>asList(String.class, Integer.class, Boolean.class, Long.class, Byte.class, Short.class, Character.class, Float.class, Double.class);
private static final Map<Class<?>, ConfigurationValueParser> SIMPLE_TYPES;
static {
Map<Class<?>, ConfigurationValueParser> map = new HashMap<Class<?>, ConfigurationValueParser>();
map.put(String.class, new ConfigurationValueParser() {
@Override public Object parse(String value) {
return value;
}
@Override public String description() {
return "String";
}
});
map.put(Integer.class, new ConfigurationValueParser() {
@Override public Object parse(String value) {
return Integer.parseInt(value);
}
@Override public String description() {
return "Integer";
}
});
map.put(Long.class, new ConfigurationValueParser() {
@Override public Object parse(String value) {
return Long.parseLong(value);
}
@Override public String description() {
return "Long";
}
});
map.put(Double.class, new ConfigurationValueParser() {
@Override public Object parse(String value) {
return Double.parseDouble(value);
}
@Override public String description() {
return "Double";
}
});
map.put(Boolean.class, new ConfigurationValueParser() {
@Override public Object parse(String value) {
return Boolean.parseBoolean(value);
}
@Override public String description() {
return "Boolean";
}
});
map.put(TypeName.class, new ConfigurationValueParser() {
@Override public Object parse(String value) {
return TypeName.valueOf(value);
}
@Override public String description() {
return "TypeName";
}
});
SIMPLE_TYPES = map;
}
private static ConfigurationValueParser enumParser(Object enumType) {
@SuppressWarnings("rawtypes") final Class rawType = (Class)enumType;
return new ConfigurationValueParser(){
@SuppressWarnings("unchecked")
@Override public Object parse(String value) {
try {
return Enum.valueOf(rawType, value);
} catch (Exception e) {
return Enum.valueOf(rawType, value.toUpperCase());
}
}
@Override public String description() {
return rawType.getName();
}
};
}
private final boolean isList;
private final Class<?> elementType;
private final ConfigurationValueParser parser;
public static ConfigurationDataType toDataType(Class<? extends ConfigurationKey<?>> keyClass) {
if (keyClass.getSuperclass() != ConfigurationKey.class) {
@@ -55,61 +125,46 @@ public final class ConfigurationDataType {
}
}
if (SIMPLE_TYPES.contains(argumentType) || isEnum(argumentType)) {
return new ConfigurationDataType(isList, (Class<?>)argumentType);
if (SIMPLE_TYPES.containsKey(argumentType)) {
return new ConfigurationDataType(isList, SIMPLE_TYPES.get(argumentType));
}
if (argumentType instanceof ParameterizedType) {
ParameterizedType parameterizedArgument = (ParameterizedType) argumentType;
if (parameterizedArgument.getRawType() == Class.class) {
Type classType = parameterizedArgument.getActualTypeArguments()[0];
if (!(classType instanceof WildcardType)) {
throw new IllegalArgumentException("Illegal specific Class type parameter in " + type);
}
WildcardType wildcard = (WildcardType) classType;
if (wildcard.getLowerBounds().length != 0 || wildcard.getUpperBounds().length != 1 || wildcard.getUpperBounds()[0] != Object.class) {
throw new IllegalArgumentException("Illegal bound wildcard Class type parameter in " + type);
}
return new ConfigurationDataType(isList, Class.class);
}
}
if (argumentType == Class.class) {
return new ConfigurationDataType(isList, Class.class);
if (isEnum(argumentType)) {
return new ConfigurationDataType(isList, enumParser(argumentType));
}
throw new IllegalArgumentException("Unsupported type parameter in " + type);
}
private ConfigurationDataType(boolean isList, Class<?> elementType) {
private ConfigurationDataType(boolean isList, ConfigurationValueParser parser) {
this.isList = isList;
this.elementType = elementType;
this.parser = parser;
}
public boolean isList() {
boolean isList() {
return isList;
}
public Class<?> getElementType() {
return elementType;
ConfigurationValueParser getParser() {
return parser;
}
@Override
public int hashCode() {
return (isList ? 1231 : 1237) + elementType.hashCode();
return (isList ? 1231 : 1237) + parser.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ConfigurationDataType)) return false;
ConfigurationDataType other = (ConfigurationDataType) obj;
return isList == other.isList && elementType == other.elementType;
return isList == other.isList && parser.equals(other.parser);
}
@Override
public String toString() {
if (isList) return "java.util.List<" + elementType.getName() + ">";
return elementType.getName();
if (isList) return "List<" + parser.description() + ">";
return parser.description();
}
private static boolean isEnum(Type argumentType) {
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.core.configuration;
interface ConfigurationValueParser {
Object parse(String value);
String description();
}
@@ -21,8 +21,11 @@
*/
package lombok.core.configuration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -30,16 +33,31 @@ public class StringResolver implements ConfigurationResolver {
private static final Pattern LINE = Pattern.compile("(?:clear\\s+([^=]+))|(?:(\\S*?)\\s*([-+]?=)\\s*(.*?))");
private final Map<String, Result> values = new TreeMap<String, Result>(String.CASE_INSENSITIVE_ORDER);
private static class Result {
Object value;
boolean owned;
public Result(Object value, boolean owned) {
this.value = value;
this.owned = owned;
}
@Override public String toString() {
return String.valueOf(value) + (owned ? " (set)" : " (delta)");
}
}
public StringResolver(String content) {
Map<String, ConfigurationDataType> registeredKeys = ConfigurationKey.registeredKeys();
for (String line : content.trim().split("\\s*\\n\\s*")) {
if (line.isEmpty() || line.startsWith("#")) continue;
Matcher matcher = LINE.matcher(line);
System.out.println("\nLINE: " + line);
String operator = null;
String keyName = null;
String value = null;
String value;
if (matcher.matches()) {
if (matcher.group(1) == null) {
@@ -61,24 +79,91 @@ public class StringResolver implements ConfigurationResolver {
} else if (operator.equals("=") && type.isList()) {
System.out.println(keyName + " IS a list");
} else {
System.out.printf("!! %s %s %s", keyName, operator, value);
processResult(keyName, operator, value, type);
}
}
} else {
System.out.println("no match:" + line);
}
}
for (Result r : values.values()) {
if (r.value instanceof List<?>) {
r.value = Collections.unmodifiableList(((List<?>) r.value));
}
}
}
@Override public <T> T resolve(ConfigurationKey<T> key) {
return null;
}
public static void main(String[] args) {
ConfigurationKey<String> AAP = new ConfigurationKey<String>("aap") {};
ConfigurationKey<List<String>> NOOT = new ConfigurationKey<List<String>>("noot") {};
private void processResult(String keyName, String operator, String value, ConfigurationDataType type) {
Object element = null;
if (value != null) try {
element = type.getParser().parse(value);
}
catch (Exception e) {
// log the wrong value
return;
}
ConfigurationResolver resolver = new StringResolver(" aap = 3 \naap += 4\n\r noot+=mies\nnoot=wim\nclear noot\nclear aap\r\n#foo-= bar\nblablabla\na=b=c\n\n\nclear test\n\nclear \nclear test=");
String aapValue = resolver.resolve(AAP);
if (operator.equals("clear") || operator.equals("=")) {
if (element == null && type.isList()) {
element = new ArrayList<Object>();
}
values.put(keyName, new Result(element, true));
} else {
Result result = values.get(keyName);
@SuppressWarnings("unchecked")
List<Object> list = result == null ? new ArrayList<Object>() : (List<Object>) result.value;
if (result == null) values.put(keyName, new Result(list, false));
list.remove(element);
if (operator.equals("+=")) list.add(element);
}
}
@SuppressWarnings("unchecked")
@Override public <T> T resolve(ConfigurationKey<T> key) {
Result result = values.get(key.getKeyName());
T value = result == null ? null: (T)result.value;
if (value == null && key.getType().isList()) {
value = (T)Collections.emptyList();
}
return value;
}
enum Flag {
WARNING, ERROR
}
private static final ConfigurationKey<String> AAP = new ConfigurationKey<String>("aap") {};
private static final ConfigurationKey<List<String>> NOOT = new ConfigurationKey<List<String>>("noot") {};
private static final ConfigurationKey<Integer> MIES = new ConfigurationKey<Integer>("mies") {};
private static final ConfigurationKey<Boolean> WIM = new ConfigurationKey<Boolean>("wim") {};
private static final ConfigurationKey<TypeName> ZUS = new ConfigurationKey<TypeName>("zus") {};
private static final ConfigurationKey<Flag> JET = new ConfigurationKey<Flag>("jet") {};
public static void main(String[] args) {
print("aap=text\nnoot+=first\nmies=5\nwim=true\nzus=foo.bar.Baz\njet=error");
print("noot+=first\nnoot+=second\n");
print("clear noot");
print("noot+=before-clear\nclear noot\nnoot+=first\nnoot+=second\nnoot+=third\nnoot+=first\nnoot-=second\n");
}
private static void print(String content) {
StringResolver resolver = new StringResolver(content);
System.out.println("\n\n================================================");
System.out.println(content);
System.out.println("================================================\n");
System.out.println(resolver.values);
System.out.println("================================================\n");
String aap = resolver.resolve(AAP);
System.out.println("aap: "+ aap);
List<String> noot = resolver.resolve(NOOT);
System.out.println("noot: "+ noot);
Integer mies = resolver.resolve(MIES);
System.out.println("mies: "+ mies);
Boolean wim = resolver.resolve(WIM);
System.out.println("wim: "+ wim);
TypeName zus = resolver.resolve(ZUS);
System.out.println("zus: "+ zus);
Flag jet = resolver.resolve(JET);
System.out.println("jet: "+ jet);
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.core.configuration;
public final class TypeName {
private final String name;
private TypeName(String name) {
this.name = name;
}
public static TypeName valueOf(String name) {
return new TypeName(name);
}
@Override public boolean equals(Object obj) {
if (!(obj instanceof TypeName)) return false;
return name.equals(((TypeName) obj).name);
}
@Override public int hashCode() {
return name.hashCode();
}
@Override public String toString() {
return name;
}
}