Skip to content

Commit

Permalink
WELD-670 support proxying classes with private constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartwdouglas committed Sep 6, 2010
1 parent d562531 commit 48b767b
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
48 changes: 48 additions & 0 deletions impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java
Expand Up @@ -42,6 +42,7 @@
import javassist.bytecode.ClassFile;
import javassist.bytecode.DuplicateMemberException;
import javassist.bytecode.FieldInfo;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.Opcode;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyObject;
Expand Down Expand Up @@ -394,10 +395,12 @@ protected void addConstructors(ClassFile proxyClassType, Bytecode initialValueBy
}
else
{
boolean constructorFound = false;
for (Constructor<?> constructor : beanType.getDeclaredConstructors())
{
if ((constructor.getModifiers() & Modifier.PRIVATE) == 0)
{
constructorFound = true;
String[] exceptions = new String[constructor.getExceptionTypes().length];
for (int i = 0; i < exceptions.length; ++i)
{
Expand All @@ -406,6 +409,12 @@ protected void addConstructors(ClassFile proxyClassType, Bytecode initialValueBy
ConstructorUtils.addConstructor(DescriptorUtils.getConstructorDescriptor(constructor), exceptions, proxyClassType, initialValueBytecode);
}
}
if (!constructorFound)
{
// the bean only has private constructors, we need to generate
// two fake constructors that call each other
addConstructorsForBeanWithPrivateConstructors(proxyClassType);
}
}
}
catch (Exception e)
Expand Down Expand Up @@ -829,6 +838,45 @@ protected static void getDeclaredMethod(Bytecode code, String declaringClass, St
code.addInvokevirtual("java.lang.Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
}

/**
* Adds two constructors to the class that call each other in order to bypass
* the JVM class file verifier.
*
* This would result in a stack overflow if they were actually called,
* however the proxy is directly created without calling the constructor
*
*/
private void addConstructorsForBeanWithPrivateConstructors(ClassFile proxyClassType)
{
try
{
MethodInfo ctor = new MethodInfo(proxyClassType.getConstPool(), "<init>", "(Ljava/lang/Byte;)V");
Bytecode b = new Bytecode(proxyClassType.getConstPool(), 3, 3);
b.add(Opcode.ALOAD_0);
b.add(Opcode.ACONST_NULL);
b.add(Opcode.ACONST_NULL);
b.addInvokespecial(proxyClassType.getName(), "<init>", "(Ljava/lang/Byte;Ljava/lang/Byte;)V");
b.add(Opcode.RETURN);
ctor.setCodeAttribute(b.toCodeAttribute());
ctor.setAccessFlags(AccessFlag.PUBLIC);
proxyClassType.addMethod(ctor);

ctor = new MethodInfo(proxyClassType.getConstPool(), "<init>", "(Ljava/lang/Byte;Ljava/lang/Byte;)V");
b = new Bytecode(proxyClassType.getConstPool(), 3, 3);
b.add(Opcode.ALOAD_0);
b.add(Opcode.ACONST_NULL);
b.addInvokespecial(proxyClassType.getName(), "<init>", "(Ljava/lang/Byte;)V");
b.add(Opcode.RETURN);
ctor.setCodeAttribute(b.toCodeAttribute());
ctor.setAccessFlags(AccessFlag.PUBLIC);
proxyClassType.addMethod(ctor);
}
catch (DuplicateMemberException e)
{
throw new RuntimeException(e);
}
}

public Class<?> getBeanType()
{
return beanType;
Expand Down
9 changes: 8 additions & 1 deletion impl/src/main/java/org/jboss/weld/util/Proxies.java
Expand Up @@ -225,7 +225,14 @@ private static UnproxyableResolutionException getUnproxyableClassException(Class
}
else if (Modifier.isPrivate(constructor.getModifiers()))
{
return new UnproxyableResolutionException(NOT_PROXYABLE_PRIVATE_CONSTRUCTOR, clazz, constructor);
if (!InstantiatorFactory.useInstantiators())
{
return new UnproxyableResolutionException(NOT_PROXYABLE_PRIVATE_CONSTRUCTOR, clazz, constructor);
}
else
{
return null;
}
}
else if (Reflections.isTypeOrAnyMethodFinal(clazz))
{
Expand Down

0 comments on commit 48b767b

Please sign in to comment.