[configuration] ongoing work on the typing and resolving

This commit is contained in:
Roel Spilker committed 2013-12-18 22:44:13 +01:00
1 parent 404956374e
commit 43ead7d65f
7 files changed
+386 -18

No files matched your search

+1 -1
View File
@@ -36,7 +36,7 @@ import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import lombok.core.LombokConfiguration.ConfigurationKey;
import lombok.core.configuration.ConfigurationKey;
/**
* Lombok wraps the AST produced by a target platform into its own AST system, mostly because both Eclipse and javac
+47 -16
View File
@@ -21,7 +21,11 @@
*/
package lombok.core;
import java.lang.reflect.Type;
import java.util.List;
import javax.lang.model.SourceVersion;
import lombok.core.configuration.ConfigurationKey;
public class LombokConfiguration {
@@ -29,23 +33,50 @@ public class LombokConfiguration {
// prevent instantiation
}
/*
* Typical usage: use this as a supertypetoken.
*/
public abstract static class ConfigurationKey<T> {
private final String keyName;
public ConfigurationKey(String keyName) {
this.keyName = keyName;
System.out.println("registering " + keyName);
}
}
@SuppressWarnings("unchecked")
static <T> T read(ConfigurationKey<T> key, AST<?, ?, ?> ast) {
Type it = key.getClass().getGenericSuperclass();
if (key.keyName.equals("lombok.log.varName")) return (T)"loggertje";
if (key.keyName.equals("lombok.log.static")) return (T)Boolean.FALSE;
// if (key.keyName.equals("lombok.log.varName")) return (T)"loggertje";
// if (key.keyName.equals("lombok.log.static")) return (T)Boolean.FALSE;
return null;
}
@SuppressWarnings("rawtypes")
public static void main(String[] args) {
try { new ConfigurationKey<List<String>>("List<String>") {}; } catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<Integer>("Integer") {}; } catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<Class<?>>("Class<?>") {}; } catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<SourceVersion>("SourceVersion") {}; } catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<Class>("Class") {}; } catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<Class<Number>>("Class<Number>") {}; } catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<Class<? extends Number>>("Class<? extends Number>") {}; } catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<Class<? super String>>("Class<? super String>") {}; } catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<Number>("Number") {}; } catch (Exception e) { e.printStackTrace();}
try { class Between extends ConfigurationKey<String> {
public Between() {
super("between");
}
};
new Between(){};
} catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<String>("more than once") {}; } catch (Exception e) { e.printStackTrace();}
try { new ConfigurationKey<Integer>("more than once") {}; } catch (Exception e) { e.printStackTrace();}
System.out.println(System.identityHashCode(ConfigurationKey.registeredKeys()));
System.out.println(System.identityHashCode(ConfigurationKey.registeredKeys()));
ConfigurationKey<?> first = null;
try { first = new ConfigurationKey<Integer>("anint") {}; } catch (Exception e) { e.printStackTrace();}
System.out.println(System.identityHashCode(ConfigurationKey.registeredKeys()));
System.out.println(System.identityHashCode(ConfigurationKey.registeredKeys()));
ConfigurationKey<?> second = null;
try { second = new ConfigurationKey<Integer>("anint") {}; } catch (Exception e) { e.printStackTrace();}
System.out.println(System.identityHashCode(ConfigurationKey.registeredKeys()));
System.out.println(System.identityHashCode(ConfigurationKey.registeredKeys()));
System.out.println(first == second);
System.out.println(first.getClass() == second.getClass());
System.out.println(first.equals(second));
}
}
@@ -0,0 +1,118 @@
/*
* 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;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.List;
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 final boolean isList;
private final Class<?> elementType;
public static ConfigurationDataType toDataType(Class<? extends ConfigurationKey<?>> keyClass) {
if (keyClass.getSuperclass() != ConfigurationKey.class) {
throw new IllegalArgumentException("No direct subclass of ConfigurationKey: " + keyClass.getName());
}
Type type = keyClass.getGenericSuperclass();
if (!(type instanceof ParameterizedType)) {
throw new IllegalArgumentException("Missing type parameter in "+ type);
}
ParameterizedType parameterized = (ParameterizedType) type;
Type argumentType = parameterized.getActualTypeArguments()[0];
boolean isList = false;
if (argumentType instanceof ParameterizedType) {
ParameterizedType parameterizedArgument = (ParameterizedType) argumentType;
if (parameterizedArgument.getRawType() == List.class) {
isList = true;
argumentType = parameterizedArgument.getActualTypeArguments()[0];
}
}
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 (argumentType == Class.class) {
return new ConfigurationDataType(isList, Class.class);
}
throw new IllegalArgumentException("Unsupported type parameter in " + type);
}
private ConfigurationDataType(boolean isList, Class<?> elementType) {
this.isList = isList;
this.elementType = elementType;
}
public boolean isList() {
return isList;
}
public Class<?> getElementType() {
return elementType;
}
@Override
public int hashCode() {
return (isList ? 1231 : 1237) + elementType.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ConfigurationDataType)) return false;
ConfigurationDataType other = (ConfigurationDataType) obj;
return isList == other.isList && elementType == other.elementType;
}
@Override
public String toString() {
if (isList) return "java.util.List<" + elementType.getName() + ">";
return elementType.getName();
}
private static boolean isEnum(Type argumentType) {
return argumentType instanceof Class && ((Class<?>) argumentType).isEnum();
}
}
@@ -0,0 +1,109 @@
/*
* 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;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Describes a configuration key and its type.
* <p>
* The recommended usage is to create a type token:
* <pre>
* private static ConfigurationKey&lt;String> KEY = new ConfigurationKey&lt;String>("keyName") {};
* </pre>
*/
public abstract class ConfigurationKey<T> {
private static final Map<String, ConfigurationDataType> registeredKeys = new HashMap<String, ConfigurationDataType>();
private static Map<String, ConfigurationDataType> copy;
private final String keyName;
private final ConfigurationDataType type;
public ConfigurationKey(String keyName) {
this.keyName = checkName(keyName);
@SuppressWarnings("unchecked")
ConfigurationDataType type = ConfigurationDataType.toDataType((Class<? extends ConfigurationKey<?>>)getClass());
this.type = type;
registerKey(keyName, type);
}
public final String getKeyName() {
return keyName;
}
public final ConfigurationDataType getType() {
return type;
}
@Override
public final int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + keyName.hashCode();
result = prime * result + type.hashCode();
return result;
}
/**
* Two configuration are considered equal if and only if their {@code keyName} and {@code type} are equal.
*/
@Override
public final boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ConfigurationKey)) return false;
ConfigurationKey<?> other = (ConfigurationKey<?>) obj;
return keyName.equals(other.keyName) && type.equals(other.type);
}
private static String checkName(String keyName) {
if (keyName == null) throw new NullPointerException("keyName");
if (keyName.contains("=")) throw new IllegalArgumentException("Invalid character '=' in keyName: " + keyName);
return keyName;
}
/**
* Returns a copy of the currently registered keys.
*/
public static Map<String, ConfigurationDataType> registeredKeys() {
synchronized (registeredKeys) {
if (copy == null) copy = Collections.unmodifiableMap(new HashMap<String, ConfigurationDataType>(registeredKeys));
return copy;
}
}
private static void registerKey(String keyName, ConfigurationDataType type) {
synchronized (registeredKeys) {
ConfigurationDataType existingType = registeredKeys.get(keyName);
if (existingType == null) {
registeredKeys.put(keyName, type);
copy = null;
return;
}
if (!existingType.equals(type)) {
throw new IllegalArgumentException("Key '" + keyName + "' already registered with a different type, existing " + existingType + " != provided " + type);
}
}
}
}
@@ -0,0 +1,26 @@
/*
* 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 interface ConfigurationResolver {
<T> T resolve(ConfigurationKey<T> key);
}
@@ -0,0 +1,84 @@
/*
* 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;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StringResolver implements ConfigurationResolver {
private static final Pattern LINE = Pattern.compile("(?:clear\\s+([^=]+))|(?:(\\S*?)\\s*([-+]?=)\\s*(.*?))");
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;
if (matcher.matches()) {
if (matcher.group(1) == null) {
keyName = matcher.group(2);
operator = matcher.group(3);
value = matcher.group(4);
} else {
keyName = matcher.group(1);
operator = "clear";
value = null;
}
ConfigurationDataType type = registeredKeys.get(keyName);
if (type == null) {
System.out.println("Unknown key " + keyName);
} else {
boolean listOperator = operator.equals("+=") || operator.equals("-=");
if (listOperator && !type.isList()) {
System.out.println(keyName + " is not a list");
} else if (operator.equals("=") && type.isList()) {
System.out.println(keyName + " IS a list");
} else {
System.out.printf("!! %s %s %s", keyName, operator, value);
}
}
} else {
System.out.println("no match:" + line);
}
}
}
@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") {};
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);
}
}
@@ -28,7 +28,7 @@ import java.lang.reflect.Modifier;
import java.util.Arrays;
import lombok.core.AnnotationValues;
import lombok.core.LombokConfiguration.ConfigurationKey;
import lombok.core.configuration.ConfigurationKey;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult;