You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/05/31 00:19:42 UTC
incubator-juneau git commit: Fix race condition in
BeanContext/ClassMeta
Repository: incubator-juneau
Updated Branches:
refs/heads/master c4952d2cf -> ce2d7fbe1
Fix race condition in BeanContext/ClassMeta
Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/ce2d7fbe
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/ce2d7fbe
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/ce2d7fbe
Branch: refs/heads/master
Commit: ce2d7fbe1e53d4e9f2210e19101e5cc78b0c82ea
Parents: c4952d2
Author: JamesBognar <ja...@apache.org>
Authored: Tue May 30 20:19:40 2017 -0400
Committer: JamesBognar <ja...@apache.org>
Committed: Tue May 30 20:19:40 2017 -0400
----------------------------------------------------------------------
.../java/org/apache/juneau/BeanContext.java | 15 +++
.../org/apache/juneau/BeanPropertyValue.java | 9 ++
.../main/java/org/apache/juneau/ClassMeta.java | 105 +++++++++++--------
3 files changed, 85 insertions(+), 44 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ce2d7fbe/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
index 5b1f166..69fd415 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
@@ -1048,6 +1048,19 @@ public class BeanContext extends Context {
* Otherwise, returns a new {@link ClassMeta} object every time.<br>
*/
public final <T> ClassMeta<T> getClassMeta(Class<T> type) {
+ return getClassMeta(type, true);
+ }
+
+ /**
+ * Construct a {@code ClassMeta} wrapper around a {@link Class} object.
+ *
+ * @param <T> The class type being wrapped.
+ * @param type The class to resolve.
+ * @param waitForInit If <jk>true</jk>, wait for the ClassMeta constructor to finish before returning.
+ * @return If the class is not an array, returns a cached {@link ClassMeta} object.
+ * Otherwise, returns a new {@link ClassMeta} object every time.<br>
+ */
+ final <T> ClassMeta<T> getClassMeta(Class<T> type, boolean waitForInit) {
// If this is an array, then we want it wrapped in an uncached ClassMeta object.
// Note that if it has a pojo swap, we still want to cache it so that
@@ -1069,6 +1082,8 @@ public class BeanContext extends Context {
cm = new ClassMeta<T>(type, this, findImplClass(type), findBeanFilter(type), findPojoSwap(type), findChildPojoSwaps(type));
}
}
+ if (waitForInit)
+ cm.waitForInit();
return cm;
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ce2d7fbe/juneau-core/src/main/java/org/apache/juneau/BeanPropertyValue.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyValue.java b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyValue.java
index 68abb37..856968c 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyValue.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyValue.java
@@ -82,4 +82,13 @@ public class BeanPropertyValue implements Comparable<BeanPropertyValue> {
public int compareTo(BeanPropertyValue o) {
return name.compareTo(o.name);
}
+
+ @Override /* Object */
+ public String toString() {
+ return new ObjectMap()
+ .append("name", name)
+ .append("value", value)
+ .append("type", pMeta.getClassMeta().getInnerClass().getSimpleName())
+ .toString();
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ce2d7fbe/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
index 4c1a333..e560080 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
@@ -22,6 +22,7 @@ import java.net.*;
import java.net.URI;
import java.util.*;
import java.util.concurrent.*;
+import java.util.concurrent.locks.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.internal.*;
@@ -117,6 +118,9 @@ public final class ClassMeta<T> implements Type {
private static final Double DOUBLE_DEFAULT = 0d;
private static final Byte BYTE_DEFAULT = (byte)0;
+ private ReadWriteLock lock = new ReentrantReadWriteLock(false);
+ private Lock rLock = lock.readLock(), wLock = lock.writeLock();
+
/**
* Construct a new {@code ClassMeta} based on the specified {@link Class}.
*
@@ -139,49 +143,62 @@ public final class ClassMeta<T> implements Type {
this.innerClass = innerClass;
this.beanContext = beanContext;
- // We always immediately add this class meta to the bean context cache so that we can resolve recursive references.
- if (beanContext != null && beanContext.cmCache != null)
- beanContext.cmCache.put(innerClass, this);
-
- ClassMetaBuilder<T> builder = new ClassMetaBuilder(innerClass, beanContext, implClass, beanFilter, pojoSwap, childPojoSwaps);
-
- this.cc = builder.cc;
- this.isDelegate = builder.isDelegate;
- this.fromStringMethod = builder.fromStringMethod;
- this.swapMethod = builder.swapMethod;
- this.unswapMethod = builder.unswapMethod;
- this.swapMethodType = builder.swapMethodType;
- this.parentPropertyMethod = builder.parentPropertyMethod;
- this.namePropertyMethod = builder.namePropertyMethod;
- this.noArgConstructor = builder.noArgConstructor;
- this.stringConstructor = builder.stringConstructor;
- this.swapConstructor = builder.swapConstructor;
- this.numberConstructor = builder.numberConstructor;
- this.numberConstructorType = builder.numberConstructorType;
- this.primitiveDefault = builder.primitiveDefault;
- this.publicMethods = builder.publicMethods;
- this.remoteableMethods = builder.remoteableMethods;
- this.beanFilter = beanFilter;
- this.pojoSwap = builder.pojoSwap;
- this.extMeta = new MetadataMap();
- this.keyType = builder.keyType;
- this.valueType = builder.valueType;
- this.elementType = builder.elementType;
- this.notABeanReason = builder.notABeanReason;
- this.beanMeta = builder.beanMeta;
- this.initException = builder.initException;
- this.typePropertyName = builder.typePropertyName;
- this.dictionaryName = builder.dictionaryName;
- this.serializedClassMeta = builder.serializedClassMeta;
- this.invocationHandler = builder.invocationHandler;
- this.beanRegistry = builder.beanRegistry;
- this.isMemberClass = builder.isMemberClass;
- this.isAbstract = builder.isAbstract;
- this.implClass = builder.implClass;
- this.childUnswapMap = builder.childUnswapMap;
- this.childSwapMap = builder.childSwapMap;
- this.childPojoSwaps = builder.childPojoSwaps;
- this.args = null;
+ wLock.lock();
+ try {
+ // We always immediately add this class meta to the bean context cache so that we can resolve recursive references.
+ if (beanContext != null && beanContext.cmCache != null)
+ beanContext.cmCache.put(innerClass, this);
+
+ ClassMetaBuilder<T> builder = new ClassMetaBuilder(innerClass, beanContext, implClass, beanFilter, pojoSwap, childPojoSwaps);
+
+ this.cc = builder.cc;
+ this.isDelegate = builder.isDelegate;
+ this.fromStringMethod = builder.fromStringMethod;
+ this.swapMethod = builder.swapMethod;
+ this.unswapMethod = builder.unswapMethod;
+ this.swapMethodType = builder.swapMethodType;
+ this.parentPropertyMethod = builder.parentPropertyMethod;
+ this.namePropertyMethod = builder.namePropertyMethod;
+ this.noArgConstructor = builder.noArgConstructor;
+ this.stringConstructor = builder.stringConstructor;
+ this.swapConstructor = builder.swapConstructor;
+ this.numberConstructor = builder.numberConstructor;
+ this.numberConstructorType = builder.numberConstructorType;
+ this.primitiveDefault = builder.primitiveDefault;
+ this.publicMethods = builder.publicMethods;
+ this.remoteableMethods = builder.remoteableMethods;
+ this.beanFilter = beanFilter;
+ this.pojoSwap = builder.pojoSwap;
+ this.extMeta = new MetadataMap();
+ this.keyType = builder.keyType;
+ this.valueType = builder.valueType;
+ this.elementType = builder.elementType;
+ this.notABeanReason = builder.notABeanReason;
+ this.beanMeta = builder.beanMeta;
+ this.initException = builder.initException;
+ this.typePropertyName = builder.typePropertyName;
+ this.dictionaryName = builder.dictionaryName;
+ this.serializedClassMeta = builder.serializedClassMeta;
+ this.invocationHandler = builder.invocationHandler;
+ this.beanRegistry = builder.beanRegistry;
+ this.isMemberClass = builder.isMemberClass;
+ this.isAbstract = builder.isAbstract;
+ this.implClass = builder.implClass;
+ this.childUnswapMap = builder.childUnswapMap;
+ this.childSwapMap = builder.childSwapMap;
+ this.childPojoSwaps = builder.childPojoSwaps;
+ this.args = null;
+ } finally {
+ wLock.unlock();
+ }
+ }
+
+ /**
+ * Causes thread to wait until constructor has exited.
+ */
+ final void waitForInit() {
+ rLock.lock();
+ rLock.unlock();
}
/**
@@ -687,7 +704,7 @@ public final class ClassMeta<T> implements Type {
}
private ClassMeta<?> findClassMeta(Class<?> c) {
- return beanContext.getClassMeta(c);
+ return beanContext.getClassMeta(c, false);
}
private ClassMeta<?>[] findParameters() {