diff options
4 files changed, 255 insertions, 41 deletions
diff --git a/src/core/lombok/core/configuration/ConfigurationDataType.java b/src/core/lombok/core/configuration/ConfigurationDataType.java index 5a8c37f1..d33de9e4 100644 --- a/src/core/lombok/core/configuration/ConfigurationDataType.java +++ b/src/core/lombok/core/configuration/ConfigurationDataType.java @@ -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 (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 (SIMPLE_TYPES.containsKey(argumentType)) { + return new ConfigurationDataType(isList, SIMPLE_TYPES.get(argumentType)); } - 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) { diff --git a/src/core/lombok/core/configuration/ConfigurationValueParser.java b/src/core/lombok/core/configuration/ConfigurationValueParser.java new file mode 100644 index 00000000..e0c356f8 --- /dev/null +++ b/src/core/lombok/core/configuration/ConfigurationValueParser.java @@ -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(); +}
\ No newline at end of file diff --git a/src/core/lombok/core/configuration/StringResolver.java b/src/core/lombok/core/configuration/StringResolver.java index d939d916..81bd0a35 100644 --- a/src/core/lombok/core/configuration/StringResolver.java +++ b/src/core/lombok/core/configuration/StringResolver.java @@ -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)); + } + } } + 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; + } + + 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) { - return null; + 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) { - ConfigurationKey<String> AAP = new ConfigurationKey<String>("aap") {}; - ConfigurationKey<List<String>> NOOT = new ConfigurationKey<List<String>>("noot") {}; - - 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); + 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); } } diff --git a/src/core/lombok/core/configuration/TypeName.java b/src/core/lombok/core/configuration/TypeName.java new file mode 100644 index 00000000..989e1b97 --- /dev/null +++ b/src/core/lombok/core/configuration/TypeName.java @@ -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; + } +} |