http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java b/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java new file mode 100644 index 0000000..e621729 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * This class contains utility methods to determine which class called the + * current class to multiple levels of depth. Calls used to handle the + * groovy MOP are excluded from the level counting. + */ +public class ReflectionUtils { + + // these are packages in the call stack that are only part of the groovy MOP + private static final Set<String> IGNORED_PACKAGES = new HashSet<String>(); + + static { + //IGNORED_PACKAGES.add("java.lang.reflect"); + IGNORED_PACKAGES.add("groovy.lang"); + IGNORED_PACKAGES.add("org.codehaus.groovy.reflection"); + IGNORED_PACKAGES.add("org.codehaus.groovy.runtime.callsite"); + IGNORED_PACKAGES.add("org.codehaus.groovy.runtime.metaclass"); + IGNORED_PACKAGES.add("org.codehaus.groovy.runtime"); + IGNORED_PACKAGES.add("sun.reflect"); + IGNORED_PACKAGES.add("java.lang.invoke"); + IGNORED_PACKAGES.add("org.codehaus.groovy.vmplugin.v7"); + } + + private static final ClassContextHelper HELPER = new ClassContextHelper(); + + /** + * Determine whether or not the getCallingClass methods will return + * any sensible results. On JVMs that are not Sun derived i.e. + * (gcj, Harmony) this will likely return false. When not available + * all getCallingClass methods will return null. + * + * @return true if getCallingClass can return anything but null, false if + * it will only return null. + */ + public static boolean isCallingClassReflectionAvailable() { + return true; + } + + /** + * Get the immediate calling class, ignoring MOP frames. + * + * @return The Class of the caller + */ + public static Class getCallingClass() { + return getCallingClass(1); + } + + /** + * Get the called that is matchLevel stack frames before the call, + * ignoring MOP frames. + * + * @param matchLevel how may call stacks down to look. + * If it is less than 1 it is treated as though it was 1. + * @return The Class of the matched caller, or null if there aren't + * enough stackframes to satisfy matchLevel + */ + public static Class getCallingClass(int matchLevel) { + return getCallingClass(matchLevel, Collections.EMPTY_SET); + } + + /** + * Get the called that is matchLevel stack frames before the call, + * ignoring MOP frames and desired exclude packages. + * + * @param matchLevel how may call stacks down to look. + * If it is less than 1 it is treated as though it was 1. + * @param extraIgnoredPackages A collection of string names of packages to exclude + * in addition to the MOP packages when counting stack frames. + * @return The Class of the matched caller, or null if there aren't + * enough stackframes to satisfy matchLevel + */ + public static Class getCallingClass(int matchLevel, Collection<String> extraIgnoredPackages) { + Class[] classContext = HELPER.getClassContext(); + + int depth = 0; + try { + Class c; + // this super class stuff is for Java 1.4 support only + // it isn't needed on a 5.0 VM + Class sc; + do { + do { + c = classContext[depth++]; + if (c != null) { + sc = c.getSuperclass(); + } else { + sc = null; + } + } while (classShouldBeIgnored(c, extraIgnoredPackages) + || superClassShouldBeIgnored(sc)); + } while (c != null && matchLevel-- > 0 && depth<classContext.length); + return c; + } catch (Throwable t) { + return null; + } + } + + private static boolean superClassShouldBeIgnored(Class sc) { + return ((sc != null) && (sc.getPackage() != null) && "org.codehaus.groovy.runtime.callsite".equals(sc.getPackage().getName())); + } + + private static boolean classShouldBeIgnored(Class c, Collection<String> extraIgnoredPackages) { + return ((c != null) + && (c.isSynthetic() + || (c.getPackage() != null + && (IGNORED_PACKAGES.contains(c.getPackage().getName()) + || extraIgnoredPackages.contains(c.getPackage().getName()))))); + } + + private static class ClassContextHelper extends SecurityManager { + @Override + public Class[] getClassContext() { + return super.getClassContext(); + } + } +}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/SunClassLoader.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/SunClassLoader.java b/src/main/java/org/codehaus/groovy/reflection/SunClassLoader.java new file mode 100644 index 0000000..0a6a082 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/SunClassLoader.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.io.IOException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Map; + +/** + * Special class loader, which when running on Sun VM allows to generate accessor classes for any method + */ +public class SunClassLoader extends ClassLoader implements Opcodes { + protected final Map<String,Class> knownClasses = new HashMap<String,Class>(); + + protected static final SunClassLoader sunVM; + + static { + SunClassLoader res; + try { + res = AccessController.doPrivileged(new PrivilegedAction<SunClassLoader>() { + public SunClassLoader run() { + try { + return new SunClassLoader(); + } catch (Throwable e) { + return null; + } + } + }); + } + catch (Throwable e) { + res = null; + } + sunVM = res; + } + + protected SunClassLoader() throws Throwable { + super (SunClassLoader.class.getClassLoader()); + + final Class magic = ClassLoader.getSystemClassLoader().loadClass("sun.reflect.MagicAccessorImpl"); + knownClasses.put("sun.reflect.MagicAccessorImpl", magic); + loadMagic (); + } + + private void loadMagic() { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + cw.visit(Opcodes.V1_4, Opcodes.ACC_PUBLIC, "sun/reflect/GroovyMagic", null, "sun/reflect/MagicAccessorImpl", null); + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "sun/reflect/MagicAccessorImpl", "<init>", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(0,0); + mv.visitEnd(); + cw.visitEnd(); + + define(cw.toByteArray(), "sun.reflect.GroovyMagic"); + } + + protected void loadFromRes(String name) throws IOException { + final InputStream asStream = SunClassLoader.class.getClassLoader().getResourceAsStream(resName(name)); + ClassReader reader = new ClassReader(asStream); + final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + reader.accept(cw, ClassWriter.COMPUTE_MAXS); + asStream.close(); + define(cw.toByteArray(), name); + } + + protected static String resName(String s) { + return s.replace('.','/') + ".class"; + } + + protected void define(byte[] bytes, final String name) { + knownClasses.put(name, defineClass(name, bytes, 0, bytes.length)); + } + + protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + final Class aClass = knownClasses.get(name); + if (aClass != null) + return aClass; + else { + try { + return super.loadClass(name, resolve); + } + catch (ClassNotFoundException e) { + return getClass().getClassLoader().loadClass(name); + } + } + } + + public Class doesKnow(String name) { + return knownClasses.get(name); + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/android/AndroidSupport.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/android/AndroidSupport.java b/src/main/java/org/codehaus/groovy/reflection/android/AndroidSupport.java new file mode 100644 index 0000000..67416e9 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/android/AndroidSupport.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.android; + +public abstract class AndroidSupport { + private static final boolean IS_ANDROID; + + static { + boolean isAndroid = true; + try { + Class.forName("android.app.Activity", false, AndroidSupport.class.getClassLoader()); + } catch (ClassNotFoundException e) { + isAndroid = false; + } + IS_ANDROID = isAndroid; + } + + public static boolean isRunningAndroid() { + return IS_ANDROID; + } + +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/package.html ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/package.html b/src/main/java/org/codehaus/groovy/reflection/package.html new file mode 100644 index 0000000..a01a2dd --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/package.html @@ -0,0 +1,28 @@ +<!-- + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + +--> +<html> + <head> + <title>package org.codehaus.groovy.reflection.*</title> + </head> + <body> + <p>Internal classes for assisting with reflection.</p> + </body> +</html> http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/ArrayCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/ArrayCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ArrayCachedClass.java new file mode 100644 index 0000000..fcf2908 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ArrayCachedClass.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import groovy.lang.GString; +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ClassInfo; +import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; + +/** + * @author Alex.Tkachman + */ +public class ArrayCachedClass extends CachedClass { + public ArrayCachedClass(Class klazz, ClassInfo classInfo) { + super(klazz, classInfo); + } + + public Object coerceArgument(Object argument) { + Class argumentClass = argument.getClass(); + if (argumentClass.getName().charAt(0) != '[') return argument; + Class argumentComponent = argumentClass.getComponentType(); + + Class paramComponent = getTheClass().getComponentType(); + if (paramComponent.isPrimitive()) { + argument = DefaultTypeTransformation.convertToPrimitiveArray(argument, paramComponent); + } else if (paramComponent == String.class && argument instanceof GString[]) { + GString[] strings = (GString[]) argument; + String[] ret = new String[strings.length]; + for (int i = 0; i < strings.length; i++) { + ret[i] = strings[i].toString(); + } + argument = ret; + } else if (paramComponent==Object.class && argumentComponent.isPrimitive()){ + argument = DefaultTypeTransformation.primitiveArrayBox(argument); + } + return argument; + } + +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigDecimalCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigDecimalCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigDecimalCachedClass.java new file mode 100644 index 0000000..45a1c85 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigDecimalCachedClass.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.ClassInfo; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * @author Alex.Tkachman + */ +public class BigDecimalCachedClass extends DoubleCachedClass { + public BigDecimalCachedClass(Class klazz, ClassInfo classInfo) { + super(klazz, classInfo, true); + } + + public boolean isDirectlyAssignable(Object argument) { + return argument instanceof BigDecimal; + } + + public Object coerceArgument(Object argument) { + if (argument instanceof BigDecimal) { + return argument; + } else if (argument instanceof Long) { + return new BigDecimal((Long) argument); + } else if (argument instanceof BigInteger) { + return new BigDecimal((BigInteger) argument); + } + + if (argument instanceof Number) { + return new BigDecimal(((Number) argument).doubleValue()); + } + return argument; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigIntegerCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigIntegerCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigIntegerCachedClass.java new file mode 100644 index 0000000..573fc42 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigIntegerCachedClass.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.ClassInfo; + +import java.math.BigInteger; + +/** + * @author Alex.Tkachman + */ +public class BigIntegerCachedClass extends NumberCachedClass { + public BigIntegerCachedClass(Class klazz, ClassInfo classInfo) { + super(klazz, classInfo); + } + + public boolean isDirectlyAssignable(Object argument) { + return argument instanceof BigInteger; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return classToTransformFrom == null + || classToTransformFrom == Integer.class + || classToTransformFrom == Short.class + || classToTransformFrom == Byte.class + || classToTransformFrom == BigInteger.class + || classToTransformFrom == Long.class + || classToTransformFrom == Integer.TYPE + || classToTransformFrom == Short.TYPE + || classToTransformFrom == Byte.TYPE + || classToTransformFrom == Long.TYPE + || BigInteger.class.isAssignableFrom(classToTransformFrom); + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/BooleanCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/BooleanCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BooleanCachedClass.java new file mode 100644 index 0000000..9dacdf4 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BooleanCachedClass.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ClassInfo; + +/** + * @author Alex.Tkachman + */ +public class BooleanCachedClass extends CachedClass { + private final boolean allowNull; + public BooleanCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) { + super(klazz, classInfo); + this.allowNull = allowNull; + } + + public boolean isDirectlyAssignable(Object argument) { + return (allowNull && argument == null) || argument instanceof Boolean; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return (allowNull && classToTransformFrom == null) + || classToTransformFrom == Boolean.class + || classToTransformFrom == Boolean.TYPE; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/ByteCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/ByteCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ByteCachedClass.java new file mode 100644 index 0000000..21abd59 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ByteCachedClass.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.ClassInfo; + +/** + * @author Alex.Tkachman + */ +public class ByteCachedClass extends NumberCachedClass { + private final boolean allowNull; + public ByteCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) { + super(klazz, classInfo); + this.allowNull = allowNull; + } + + public Object coerceArgument(Object argument) { + if (argument instanceof Byte) { + return argument; + } + + if (argument instanceof Number) { + return ((Number) argument).byteValue(); + } + return argument; + } + + public boolean isDirectlyAssignable(Object argument) { + return (allowNull && argument == null) || argument instanceof Byte; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return (allowNull && classToTransformFrom == null) + || classToTransformFrom == Byte.class + || classToTransformFrom == Byte.TYPE; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedClosureClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedClosureClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedClosureClass.java new file mode 100644 index 0000000..7dcaed0 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedClosureClass.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.CachedMethod; +import org.codehaus.groovy.reflection.ClassInfo; + +public class CachedClosureClass extends CachedClass { + private final Class[] parameterTypes; + private final int maximumNumberOfParameters; + + public CachedClosureClass(Class klazz, ClassInfo classInfo) { + super(klazz, classInfo); + + CachedMethod methods [] = getMethods(); + + // set it to -1 for starters so parameterTypes will always get a type + int maximumNumberOfParameters = -1; + Class[] parameterTypes = null; + + for (CachedMethod method : methods) { + if ("doCall".equals(method.getName())) { + final Class[] pt = method.getNativeParameterTypes(); + if (pt.length > maximumNumberOfParameters) { + parameterTypes = pt; + maximumNumberOfParameters = parameterTypes.length; + } + } + } + // this line should be useless, but well, just in case + maximumNumberOfParameters = Math.max(maximumNumberOfParameters,0); + + this.maximumNumberOfParameters = maximumNumberOfParameters; + this.parameterTypes = parameterTypes; + } + + public Class[] getParameterTypes() { + return parameterTypes; + } + + public int getMaximumNumberOfParameters() { + return maximumNumberOfParameters; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java new file mode 100644 index 0000000..6364f40 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import groovy.lang.Closure; +import groovy.util.ProxyGenerator; +import org.codehaus.groovy.GroovyBugError; +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ClassInfo; +import org.codehaus.groovy.reflection.ReflectionCache; +import org.codehaus.groovy.runtime.ConvertedClosure; +import org.codehaus.groovy.transform.trait.Traits; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +public class CachedSAMClass extends CachedClass { + + private static final int ABSTRACT_STATIC_PRIVATE = + Modifier.ABSTRACT|Modifier.PRIVATE|Modifier.STATIC; + private static final int VISIBILITY = 5; // public|protected + private static final Method[] EMPTY_METHOD_ARRAY = new Method[0]; + private final Method method; + + public CachedSAMClass(Class klazz, ClassInfo classInfo) { + super(klazz, classInfo); + method = getSAMMethod(klazz); + if (method==null) throw new GroovyBugError("assigned method should not have been null!"); + } + + @Override + public boolean isAssignableFrom(Class argument) { + return argument == null || + Closure.class.isAssignableFrom(argument) || + ReflectionCache.isAssignableFrom(getTheClass(), argument); + } + + @SuppressWarnings("unchecked") + public static Object coerceToSAM(Closure argument, Method method, Class clazz, boolean isInterface) { + if (argument!=null && clazz.isAssignableFrom(argument.getClass())) { + return argument; + } + if (isInterface) { + if (Traits.isTrait(clazz)) { + Map<String,Closure> impl = Collections.singletonMap( + method.getName(), + argument + ); + return ProxyGenerator.INSTANCE.instantiateAggregate(impl,Collections.singletonList(clazz)); + } + return Proxy.newProxyInstance( + clazz.getClassLoader(), + new Class[]{clazz}, + new ConvertedClosure(argument)); + } else { + Map<String, Object> m = new HashMap<String,Object>(); + m.put(method.getName(), argument); + return ProxyGenerator.INSTANCE. + instantiateAggregateFromBaseClass(m, clazz); + } + } + + @Override + public Object coerceArgument(Object argument) { + if (argument instanceof Closure) { + Class clazz = getTheClass(); + return coerceToSAM((Closure) argument, method, clazz, clazz.isInterface()); + } else { + return argument; + } + } + + private static Method[] getDeclaredMethods(final Class c) { + try { + Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() { + public Method[] run() { + return c.getDeclaredMethods(); + } + }); + if (methods!=null) return methods; + } catch (java.security.AccessControlException ace) { + // swallow and do as if no method is available + } + return EMPTY_METHOD_ARRAY; + } + + private static void getAbstractMethods(Class c, List<Method> current) { + if (c==null || !Modifier.isAbstract(c.getModifiers())) return; + getAbstractMethods(c.getSuperclass(), current); + for (Class ci : c.getInterfaces()) { + getAbstractMethods(ci, current); + } + for (Method m : getDeclaredMethods(c)) { + if (Modifier.isPrivate(m.getModifiers())) continue; + if (Modifier.isAbstract(m.getModifiers())) current.add(m); + } + } + + private static boolean hasUsableImplementation(Class c, Method m) { + if (c==m.getDeclaringClass()) return false; + Method found; + try { + found = c.getMethod(m.getName(), m.getParameterTypes()); + int asp = found.getModifiers() & ABSTRACT_STATIC_PRIVATE; + int visible = found.getModifiers() & VISIBILITY; + if (visible !=0 && asp == 0) return true; + } catch (NoSuchMethodException e) {/*ignore*/} + if (c==Object.class) return false; + return hasUsableImplementation(c.getSuperclass(), m); + } + + private static Method getSingleNonDuplicateMethod(List<Method> current) { + if (current.isEmpty()) return null; + if (current.size()==1) return current.get(0); + Method m = current.remove(0); + for (Method m2 : current) { + if (m.getName().equals(m2.getName()) && + Arrays.equals(m.getParameterTypes(), m2.getParameterTypes())) + { + continue; + } + return null; + } + return m; + } + + /** + * returns the abstract method from a SAM type, if it is a SAM type. + * @param c the SAM class + * @return null if nothing was found, the method otherwise + */ + public static Method getSAMMethod(Class<?> c) { + try { + return getSAMMethodImpl(c); + } catch (NoClassDefFoundError ignore) { + return null; + } + } + + private static Method getSAMMethodImpl(Class<?> c) { + // SAM = single public abstract method + // if the class is not abstract there is no abstract method + if (!Modifier.isAbstract(c.getModifiers())) return null; + if (c.isInterface()) { + Method[] methods = c.getMethods(); + // res stores the first found abstract method + Method res = null; + for (Method mi : methods) { + // ignore methods, that are not abstract and from Object + if (!Modifier.isAbstract(mi.getModifiers())) continue; + // ignore trait methods which have a default implementation + if (mi.getAnnotation(Traits.Implemented.class)!=null) continue; + try { + Object.class.getMethod(mi.getName(), mi.getParameterTypes()); + continue; + } catch (NoSuchMethodException e) {/*ignore*/} + + // we have two methods, so no SAM + if (res!=null) return null; + res = mi; + } + return res; + + } else { + + LinkedList<Method> methods = new LinkedList(); + getAbstractMethods(c, methods); + if (methods.isEmpty()) return null; + ListIterator<Method> it = methods.listIterator(); + while (it.hasNext()) { + Method m = it.next(); + if (hasUsableImplementation(c, m)) it.remove(); + } + return getSingleNonDuplicateMethod(methods); + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/CharacterCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/CharacterCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CharacterCachedClass.java new file mode 100644 index 0000000..619332e --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CharacterCachedClass.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ClassInfo; + +/** + * @author Alex.Tkachman + */ +public class CharacterCachedClass extends CachedClass { + private final boolean allowNull; + + public CharacterCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) { + super(klazz, classInfo); + this.allowNull = allowNull; + } + + public boolean isDirectlyAssignable(Object argument) { + return (allowNull && argument == null) || argument instanceof Character; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return (allowNull && classToTransformFrom == null) + || classToTransformFrom == Character.class + || classToTransformFrom == Character.TYPE; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/DoubleCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/DoubleCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/DoubleCachedClass.java new file mode 100644 index 0000000..4a0f5c6 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/DoubleCachedClass.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.ClassInfo; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * @author Alex.Tkachman + */ +public class DoubleCachedClass extends NumberCachedClass { // Double, double + private final boolean allowNull; + + public DoubleCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) { + super(klazz, classInfo); + this.allowNull = allowNull; + } + + public boolean isDirectlyAssignable(Object argument) { + return (allowNull && argument == null) || argument instanceof Double; + } + + public Object coerceArgument(Object argument) { + if (argument instanceof Double) { + return argument; + } + + if (argument instanceof Number) { + Double res = ((Number) argument).doubleValue(); + if (argument instanceof BigDecimal && res.isInfinite()) { + throw new IllegalArgumentException(Double.class + " out of range while converting from BigDecimal"); + } + return res; + } + return argument; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return (allowNull && classToTransformFrom == null) + || classToTransformFrom == Double.class + || classToTransformFrom == Integer.class + || classToTransformFrom == Long.class + || classToTransformFrom == Short.class + || classToTransformFrom == Byte.class + || classToTransformFrom == Float.class + || classToTransformFrom == Double.TYPE + || classToTransformFrom == Integer.TYPE + || classToTransformFrom == Long.TYPE + || classToTransformFrom == Short.TYPE + || classToTransformFrom == Byte.TYPE + || classToTransformFrom == Float.TYPE + || classToTransformFrom == BigDecimal.class + || classToTransformFrom == BigInteger.class + || (classToTransformFrom!=null && BigDecimal.class.isAssignableFrom(classToTransformFrom)) + || (classToTransformFrom!=null && BigInteger.class.isAssignableFrom(classToTransformFrom)) + ; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/FloatCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/FloatCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/FloatCachedClass.java new file mode 100644 index 0000000..a579028 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/FloatCachedClass.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.ClassInfo; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * @author Alex.Tkachman + */ +public class FloatCachedClass extends NumberCachedClass { + private final boolean allowNull; + + public FloatCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) { + super(klazz, classInfo); + this.allowNull = allowNull; + } + + public Object coerceArgument(Object argument) { + if (argument instanceof Float) { + return argument; + } + + if (argument instanceof Number) { + Float res = ((Number) argument).floatValue(); + if (argument instanceof BigDecimal && res.isInfinite()) { + throw new IllegalArgumentException(Float.class + " out of range while converting from BigDecimal"); + } + return res; + } + return argument; + } + + public boolean isDirectlyAssignable(Object argument) { + return (allowNull && argument == null) || argument instanceof Float; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return (allowNull && classToTransformFrom == null) + || classToTransformFrom == Float.class + || classToTransformFrom == Integer.class + || classToTransformFrom == Long.class + || classToTransformFrom == Short.class + || classToTransformFrom == Byte.class + || classToTransformFrom == Float.TYPE + || classToTransformFrom == Integer.TYPE + || classToTransformFrom == Long.TYPE + || classToTransformFrom == Short.TYPE + || classToTransformFrom == Byte.TYPE + || classToTransformFrom == BigDecimal.class + || classToTransformFrom == BigInteger.class; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/IntegerCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/IntegerCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/IntegerCachedClass.java new file mode 100644 index 0000000..334a3ab --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/IntegerCachedClass.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.ClassInfo; + +import java.math.BigInteger; + +/** + * @author Alex.Tkachman + */ +public class IntegerCachedClass extends NumberCachedClass { // int, Integer + private final boolean allowNull; + + public IntegerCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) { + super(klazz, classInfo); + this.allowNull = allowNull; + } + + public Object coerceArgument(Object argument) { + if (argument instanceof Integer) { + return argument; + } + + if (argument instanceof Number) { + return ((Number) argument).intValue(); + } + return argument; + } + + public boolean isDirectlyAssignable(Object argument) { + return (allowNull && argument == null) || argument instanceof Integer; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return (allowNull && classToTransformFrom == null) + || classToTransformFrom == Integer.class + || classToTransformFrom == Short.class + || classToTransformFrom == Byte.class + || classToTransformFrom == BigInteger.class + || classToTransformFrom == Integer.TYPE + || classToTransformFrom == Short.TYPE + || classToTransformFrom == Byte.TYPE; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/LongCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/LongCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/LongCachedClass.java new file mode 100644 index 0000000..5d42b0c --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/LongCachedClass.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.ClassInfo; + +/** + * @author Alex.Tkachman + */ +public class LongCachedClass extends NumberCachedClass { + private final boolean allowNull; + + public LongCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) { + super(klazz, classInfo); + this.allowNull = allowNull; + } + + + public Object coerceArgument(Object argument) { + if (argument instanceof Long) { + return argument; + } + + if (argument instanceof Number) { + return ((Number) argument).longValue(); + } + return argument; + } + + public boolean isDirectlyAssignable(Object argument) { + return (allowNull && argument == null) || argument instanceof Long; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return (allowNull && classToTransformFrom == null) + || classToTransformFrom == Integer.class + || classToTransformFrom == Long.class + || classToTransformFrom == Short.class + || classToTransformFrom == Byte.class + || classToTransformFrom == Integer.TYPE + || classToTransformFrom == Long.TYPE + || classToTransformFrom == Short.TYPE + || classToTransformFrom == Byte.TYPE; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/NumberCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/NumberCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/NumberCachedClass.java new file mode 100644 index 0000000..311cbc2 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/NumberCachedClass.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ClassInfo; + +import java.math.BigInteger; + +/** + * @author Alex.Tkachman + */ +public class NumberCachedClass extends CachedClass { + + public NumberCachedClass(Class klazz, ClassInfo classInfo) { + super(klazz, classInfo); + } + + public Object coerceArgument(Object argument) { + if (argument instanceof Number) { + return coerceNumber(argument); + } + return argument; + + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return classToTransformFrom == null + || Number.class.isAssignableFrom(classToTransformFrom) + || classToTransformFrom == Byte.TYPE + || classToTransformFrom == Short.TYPE + || classToTransformFrom == Integer.TYPE + || classToTransformFrom == Long.TYPE + || classToTransformFrom == Float.TYPE + || classToTransformFrom == Double.TYPE + ; + } + + private Object coerceNumber(Object argument) { + Class param = getTheClass(); + if (param == Byte.class /*|| param == Byte.TYPE*/) { + argument = Byte.valueOf(((Number) argument).byteValue()); + } else if (param == BigInteger.class) { + argument = new BigInteger(String.valueOf((Number) argument)); + } + + return argument; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/ObjectCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/ObjectCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ObjectCachedClass.java new file mode 100644 index 0000000..f29acf7 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ObjectCachedClass.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ClassInfo; + +/** + * @author Alex.Tkachman + */ +public class ObjectCachedClass extends CachedClass { + public ObjectCachedClass(ClassInfo classInfo) { + super(Object.class,classInfo); + } + + public synchronized CachedClass getCachedSuperClass() { + return null; + } + + public boolean isAssignableFrom(Class argument) { + return true; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/ShortCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/ShortCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ShortCachedClass.java new file mode 100644 index 0000000..f6cccf1 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ShortCachedClass.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import org.codehaus.groovy.reflection.ClassInfo; + +/** + * @author Alex.Tkachman + */ +public class ShortCachedClass extends NumberCachedClass { + private final boolean allowNull; + + public ShortCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) { + super(klazz, classInfo); + this.allowNull = allowNull; + } + + public Object coerceArgument(Object argument) { + if (argument instanceof Short) { + return argument; + } + + if (argument instanceof Number) { + return ((Number) argument).shortValue(); + } + return argument; + } + + public boolean isDirectlyAssignable(Object argument) { + return (allowNull && argument == null) || argument instanceof Short; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return (allowNull && classToTransformFrom == null) + || classToTransformFrom == Short.class + || classToTransformFrom == Byte.class + || classToTransformFrom == Short.TYPE + || classToTransformFrom == Byte.TYPE; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/StringCachedClass.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/StringCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/StringCachedClass.java new file mode 100644 index 0000000..a3039ad --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/StringCachedClass.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.stdclasses; + +import groovy.lang.GString; +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ClassInfo; +import org.codehaus.groovy.reflection.ReflectionCache; + +/** + * @author Alex.Tkachman + */ +public class StringCachedClass extends CachedClass { + private static final Class STRING_CLASS = String.class; + private static final Class GSTRING_CLASS = GString.class; + + public StringCachedClass(ClassInfo classInfo) { + super(STRING_CLASS, classInfo); + } + + public boolean isDirectlyAssignable(Object argument) { + return argument instanceof String; + } + + public boolean isAssignableFrom(Class classToTransformFrom) { + return classToTransformFrom == null + || classToTransformFrom == STRING_CLASS + || ReflectionCache.isAssignableFrom(GSTRING_CLASS,classToTransformFrom); + } + + public Object coerceArgument(Object argument) { + return argument instanceof GString ? argument.toString() : argument; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java b/src/main/java/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java new file mode 100644 index 0000000..a964a3e --- /dev/null +++ b/src/main/java/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.reflection.v7; + +import org.codehaus.groovy.reflection.GroovyClassValue; + +/** GroovyClassValue implementaion that simply delegates to Java 7's java.lang.ClassValue + * @see java.lang.ClassValue + * + * @param <T> +*/ +public class GroovyClassValueJava7<T> extends ClassValue<T> implements GroovyClassValue<T> { + private final ComputeValue<T> computeValue; + public GroovyClassValueJava7(ComputeValue<T> computeValue){ + this.computeValue = computeValue; + } + @Override + protected T computeValue(Class<?> type) { + return computeValue.computeValue(type); + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/AbstractComparator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/runtime/AbstractComparator.java b/src/main/java/org/codehaus/groovy/runtime/AbstractComparator.java new file mode 100644 index 0000000..7c977cd --- /dev/null +++ b/src/main/java/org/codehaus/groovy/runtime/AbstractComparator.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.runtime; + +import java.util.Comparator; + +/** + * @author Andres Almiray + */ +public abstract class AbstractComparator<T> implements Comparator<T> { + public boolean equals(Object obj) { + return this == obj; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ArrayTypeUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/runtime/ArrayTypeUtils.java b/src/main/java/org/codehaus/groovy/runtime/ArrayTypeUtils.java new file mode 100644 index 0000000..2a6e409 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/runtime/ArrayTypeUtils.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.codehaus.groovy.runtime; + +/** + * Utilities for handling array types + * + * @author <a href="mailto:[email protected]">Daniel.Sun</a> + * Created on 2016/10/28 + */ +public class ArrayTypeUtils { + + /** + * Calculate the dimension of array + * + * @param clazz the type of array + * @return the dimension of array + */ + public static int dimension(Class clazz) { + checkArrayType(clazz); + + int result = 0; + while (clazz.isArray()) { + result++; + clazz = clazz.getComponentType(); + } + + return result; + } + + /** + * Get the type of array elements + * + * @param clazz the type of array + * @return the type of elements + */ + public static Class elementType(Class clazz) { + checkArrayType(clazz); + + while (clazz.isArray()) { + clazz = clazz.getComponentType(); + } + + return clazz; + } + + /** + * Reduce the dimension of array + * + * @param clazz the type of array + * @param dim the target dimension + * @return the result array + */ + public static Class reduceDimension(Class clazz, int dim) { + checkArrayType(clazz); + + if (dim < 0) { + throw new IllegalArgumentException("The target dimension should not be less than zero: " + dim); + } + + while (clazz.isArray() && dimension(clazz) > dim) { + clazz = clazz.getComponentType(); + } + + return clazz; + } + + /** + * Check whether the type passed in is array type. + * If the type is not array type, throw IllegalArgumentException. + */ + private static void checkArrayType(Class clazz) { + if (null == clazz) { + throw new IllegalArgumentException("clazz can not be null"); + } + + if (!clazz.isArray()) { + throw new IllegalArgumentException(clazz.getCanonicalName() + " is not array type"); + } + } +}
