Permalink
Browse files

Don't hard code the bean id in the proxy class, but store it in a fie…

…ld on creation

This resolves an issue when running unit tests, where the same proxy would be re-used
for beans with different bean id's
  • Loading branch information...
1 parent a99fbc2 commit fa2124d9823de78eafe689c293f13a1de6b5c796 @stuartwdouglas committed Aug 6, 2012
Showing with 42 additions and 1 deletion.
  1. +42 −1 impl/src/main/java/org/jboss/weld/bean/proxy/ClientProxyFactory.java
@@ -19,6 +19,7 @@
import java.io.ObjectStreamException;
import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
@@ -68,8 +69,22 @@
private static final String CACHE_FIELD = "BEAN_INSTANCE_CACHE";
+ /**
+ * It is possible although very unlikely that two different beans will end up with the same proxy class
+ * (generally this will only happen in test situations where weld is being started/stopped multiple times
+ * in the same class loader, such as during unit tests)
+ *
+ * To avoid this causing serialization problems we explicitly set the bean id on creation, and store it in this
+ * field.
+ *
+ *
+ */
+ private static final String BEAN_ID_FIELD = "BEAN_ID_FIELD";
+
private final String beanId;
+ private volatile Field beanIdField;
+
static {
Set<Class<? extends Annotation>> scopes = new HashSet<Class<? extends Annotation>>();
scopes.add(RequestScoped.class);
@@ -85,6 +100,24 @@ public ClientProxyFactory(Class<?> proxiedBeanType, Set<? extends Type> typeClos
}
@Override
+ public T create(BeanInstance beanInstance) {
+ try {
+ final T instance = super.create(beanInstance);
+ if (beanIdField == null) {
+ final Field f = instance.getClass().getDeclaredField(BEAN_ID_FIELD);
+ f.setAccessible(true);
+ beanIdField = f;
+ }
+ beanIdField.set(instance, beanId);
+ return instance;
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
protected void addFields(ClassFile proxyClassType, Bytecode initialValueBytecode) {
super.addFields(proxyClassType, initialValueBytecode);
if (CACHABLE_SCOPES.contains(getBean().getScope())) {
@@ -101,6 +134,13 @@ protected void addFields(ClassFile proxyClassType, Bytecode initialValueBytecode
throw new RuntimeException(e);
}
}
+ try {
+ FieldInfo beanIdField = new FieldInfo(proxyClassType.getConstPool(), BEAN_ID_FIELD, "Ljava/lang/String;");
+ beanIdField.setAccessFlags(AccessFlag.VOLATILE | AccessFlag.PRIVATE);
+ proxyClassType.addField(beanIdField);
+ } catch (DuplicateMemberException e) {
+ throw new RuntimeException(e);
+ }
}
protected void addSerializationSupport(ClassFile proxyClassType) {
@@ -121,7 +161,8 @@ private Bytecode createWriteReplaceBody(ClassFile proxyClassType) {
Bytecode b = new Bytecode(proxyClassType.getConstPool());
b.addNew(SerializableClientProxy.class.getName());
b.add(Opcode.DUP);
- b.addLdc(beanId);
+ b.add(Opcode.ALOAD_0);
+ b.addGetfield(proxyClassType.getName(), BEAN_ID_FIELD, "Ljava/lang/String;");
b.addInvokespecial(SerializableClientProxy.class.getName(), "<init>", "(Ljava/lang/String;)V");
b.add(Opcode.ARETURN);
b.setMaxLocals(1);

0 comments on commit fa2124d

Please sign in to comment.