| /* |
| * Copyright 2006 The Apache Software Foundation. |
| * |
| * Licensed 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.apache.openjpa.lib.util; |
| |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Modifier; |
| import java.security.AccessController; |
| import java.util.Arrays; |
| |
| import serp.bytecode.BCClass; |
| import serp.bytecode.BCClassLoader; |
| import serp.bytecode.BCMethod; |
| import serp.bytecode.Code; |
| import serp.bytecode.Project; |
| |
| /** |
| * Dynamically generates concrete implementations of abstract classes. |
| * |
| * @author Marc Prud'hommeaux |
| * @author Pinaki Poddar |
| * |
| * @since 1.3.0 |
| */ |
| public class ConcreteClassGenerator { |
| /** |
| * Get the constructor of the concrete, dynamic wrapper class of the given abstract class |
| * with matching argument types. |
| * @param the argTypes of the constructor to look for. null signify default constructor. |
| */ |
| public static <T> Constructor<T> getConcreteConstructor(Class<T> abstractClass, Class<?>... argTypes) |
| throws ClassNotFoundException { |
| Class<? extends T> cls = makeConcrete(abstractClass); |
| Constructor<?>[] constructors = cls.getConstructors(); |
| int args = argTypes == null ? 0 : argTypes.length; |
| for (Constructor<?> cons : constructors) { |
| Class<?>[] params = cons.getParameterTypes(); |
| if (params.length != args) |
| continue; |
| boolean match = false; |
| for (int i = 0; i < params.length; i++) { |
| match = params[i].isAssignableFrom(argTypes[i]); |
| if (!match) |
| break; |
| } |
| if (match) { |
| return (Constructor<T>)cons; |
| } |
| } |
| throw new RuntimeException(abstractClass + " has no constructor with " + |
| (args == 0 ? "void" : Arrays.toString(argTypes))); |
| } |
| |
| /** |
| * Takes an abstract class and returns a concrete implementation. Note |
| * that it doesn't actually implement any abstract methods, it |
| * merely makes an abstract class loadable. Abstract methods will |
| * throw a {@link AbstractMethodError}. |
| * |
| * @param abstractClass the abstract class |
| * @return a concrete class |
| */ |
| public static <T> Class<? extends T> makeConcrete(Class<T> abstractClass) |
| throws ClassNotFoundException { |
| if (abstractClass == null) |
| return null; |
| |
| if (!Modifier.isAbstract(abstractClass.getModifiers())) |
| return abstractClass; |
| |
| Project project = new Project(); |
| BCClassLoader loader = AccessController.doPrivileged(J2DoPrivHelper |
| .newBCClassLoaderAction(project, abstractClass.getClassLoader())); |
| |
| String name = abstractClass.getName()+"_"; |
| BCClass bc = AccessController.doPrivileged(J2DoPrivHelper. |
| loadProjectClassAction(project, name)); |
| |
| bc.setSuperclass(abstractClass); |
| |
| Constructor<?>[] constructors = abstractClass.getConstructors(); |
| if (constructors == null || constructors.length == 0) { |
| bc.addDefaultConstructor().makePublic(); |
| } else { |
| for (int i = 0; i < constructors.length; i++) { |
| Constructor<?> con = constructors[i]; |
| Class<?>[] args = con.getParameterTypes(); |
| |
| BCMethod bccon = bc.declareMethod("<init>", void.class, args); |
| Code code = bccon.getCode(true); |
| |
| code.xload().setThis(); |
| |
| for (int j = 0; j < args.length; j++) { |
| code.aload().setParam(j); |
| code.checkcast().setType(args[j]); |
| } |
| |
| code.invokespecial().setMethod(abstractClass, "<init>", void.class, args); |
| code.vreturn(); |
| |
| code.calculateMaxStack(); |
| code.calculateMaxLocals(); |
| } |
| } |
| |
| Class<?> cls = Class.forName(bc.getName(), false, loader); |
| return (Class<? extends T>)cls; |
| } |
| |
| /** |
| * Construct a new instance by the given constructor and its arguments. |
| * Hopefully faster than looking for constructor in overloaded implementations. |
| */ |
| public static <T> T newInstance(Constructor<T> cons, Object... params) { |
| try { |
| return cons.newInstance(params); |
| } catch (Exception e) { |
| throw new ExceptionInInitializerError(e); |
| } |
| } |
| |
| /** |
| * Utility method for safely invoking a constructor that we do |
| * not expect to throw exceptions. |
| * |
| * @param c the class to construct |
| * @param paramTypes the types of the parameters |
| * @param params the parameter values |
| * @return the new instance |
| */ |
| public static <T> T newInstance(Class<T> c, Class<?>[] paramTypes, Object[] params) { |
| try { |
| return c.getConstructor(paramTypes).newInstance(params); |
| } catch (Exception e) { |
| throw new ExceptionInInitializerError(e); |
| } |
| } |
| |
| /** |
| * @see #newInstance(java.lang.Class,java.lang.Class[],java.lang.Object[]) |
| */ |
| public static <T> T newInstance(Class<T> c) { |
| return newInstance(c, new Class[] { }, new Object[] { }); |
| } |
| |
| /** |
| * @see #newInstance(java.lang.Class,java.lang.Class[],java.lang.Object[]) |
| */ |
| public static <T,P> T newInstance(Class<T> c, Class<? extends P> paramType, P param) { |
| return newInstance(c, |
| new Class[] { paramType }, |
| new Object[] { param }); |
| } |
| |
| /** |
| * @see #newInstance(java.lang.Class,java.lang.Class[],java.lang.Object[]) |
| */ |
| public static <T,P1,P2> T newInstance(Class<T> c, Class<? extends P1> paramType1, P1 param1, |
| Class<? extends P2> paramType2, P2 param2) { |
| return newInstance(c, |
| new Class[] { paramType1, paramType2 }, |
| new Object[] { param1, param2 }); |
| } |
| |
| /** |
| * @see #newInstance(java.lang.Class,java.lang.Class[],java.lang.Object[]) |
| */ |
| public static <T,P1,P2,P3> T newInstance(Class<T> c, Class<? extends P1> paramType1, P1 param1, |
| Class<? extends P2> paramType2, P2 param2, Class<? extends P3> paramType3, P3 param3) { |
| return newInstance(c, |
| new Class[] { paramType1, paramType2, paramType3 }, |
| new Object[] { param1, param2, param3 }); |
| } |
| |
| /** |
| * @see #newInstance(java.lang.Class,java.lang.Class[],java.lang.Object[]) |
| */ |
| public static <T,P1,P2,P3,P4> T newInstance(Class<T> c, Class<? extends P1> paramType1, P1 param1, |
| Class<? extends P2> paramType2, P2 param2, Class<? extends P3> paramType3, P3 param3, |
| Class<? extends P4> paramType4, P4 param4) { |
| return newInstance(c, |
| new Class[] { paramType1, paramType2, paramType3, paramType4 }, |
| new Object[] { param1, param2, param3, param4 }); |
| } |
| } |
| |