Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

lighthouse-854 #259

Closed
wants to merge 1 commit into from

2 participants

@gyorfimi

Unsychronized internal cache in Binding -, solution new caching method, and immutable BeanWrapper and Property info.

@gyorfimi gyorfimi lighthouse-854
Unsychronized internal cache in Binding -, solution new caching method, and immutable BeanWrapper and Property info.
90c9762
@gyorfimi

I've renewed #235 due to requirements commented in that pull.

@mbknor
Collaborator

Thanks a lot - it's merged

@mbknor mbknor closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 8, 2011
  1. @gyorfimi

    lighthouse-854

    gyorfimi authored
    Unsychronized internal cache in Binding -, solution new caching method, and immutable BeanWrapper and Property info.
This page is out of date. Refresh to see the latest.
View
73 framework/src/play/data/binding/BeanWrapper.java
@@ -8,6 +8,8 @@
import play.classloading.enhancers.PropertiesEnhancer.PlayPropertyAccessor;
import play.exceptions.UnexpectedException;
import play.utils.Utils;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
/**
* Parameters map to POJO binder.
@@ -16,29 +18,62 @@
final static int notwritableField = Modifier.FINAL | Modifier.NATIVE | Modifier.STATIC;
final static int notaccessibleMethod = Modifier.NATIVE | Modifier.STATIC;
+ final static ConcurrentMap<Class<?>, BeanWrapper> beanWrapperCache = new ConcurrentHashMap<Class<?>, BeanWrapper>();
- private Class<?> beanClass;
+ private final Class<?> beanClass;
/**
* a cache for our properties and setters
*/
private Map<String, Property> wrappers = new HashMap<String, Property>();
- BeanWrapper(Class<?> forClass) {
+ private BeanWrapper(Class<?> forClass) {
if (Logger.isTraceEnabled()) {
Logger.trace("Bean wrapper for class %s", forClass.getName());
}
this.beanClass = forClass;
}
+
+ /**
+ * Generator method - uses thread-safe cache
+ *
+ * @param forClass the class to be wrapped
+ * @return the wrapper
+ */
+
public static BeanWrapper forClass(Class<?> forClass) {
- BeanWrapper beanWrapper = new JavaBeanWrapper(forClass);
- for (Class<?> intf: forClass.getInterfaces()) {
+ final BeanWrapper wrapper = beanWrapperCache.get(forClass);
+ if (wrapper == null) {
+ final BeanWrapper newWrapper = BeanWrapper.generateForClass(forClass);
+ /*
+ Sometimes it create an instance, but it won't be used, as
+ somebody has generated another yet, and put it into the cache
+ */
+ final BeanWrapper cachedWrapper = beanWrapperCache.putIfAbsent(forClass, newWrapper);
+
+ return cachedWrapper == null ? newWrapper : cachedWrapper;
+ /*
+ It is not thread-safe consistent to get then use put later, putIfAbsent makes it consistent,
+ it returns always the same value.
+ */
+ }
+ return wrapper;
+ }
+
+ private static BeanWrapper generateForClass(Class<?> forClass) {
+ BeanWrapper beanWrapper = null;
+ for (Class<?> intf : forClass.getInterfaces()) {
if ("scala.ScalaObject".equals(intf.getName())) {
beanWrapper = new ScalaBeanWrapper(forClass);
break;
}
}
+
+ if (beanWrapper == null) {
+ beanWrapper = new JavaBeanWrapper(forClass);
+ }
+
beanWrapper.registerSetters(forClass);
beanWrapper.registerFields(forClass);
return beanWrapper;
@@ -190,14 +225,17 @@ private void registerSetters(Class<?> clazz) {
}
}
- public static class Property {
- private Annotation[] annotations;
- private Method setter;
- private Field field;
- private Class<?> type;
- private Type genericType;
- private String name;
- private String[] profiles;
+ /**
+ * Immutable property wrapper
+ */
+ public static class Property {
+ final private Annotation[] annotations;
+ final private Method setter;
+ final private Field field;
+ final private Class<?> type;
+ final private Type genericType;
+ final private String name;
+ final private String[] profiles;
Property(String propertyName, Method setterMethod) {
name = propertyName;
@@ -205,7 +243,8 @@ private void registerSetters(Class<?> clazz) {
type = setter.getParameterTypes()[0];
annotations = setter.getAnnotations();
genericType = setter.getGenericParameterTypes()[0];
- setProfiles(this.annotations);
+ field = null;
+ profiles = createProfiles(this.annotations);
}
Property(Field field) {
@@ -215,18 +254,20 @@ private void registerSetters(Class<?> clazz) {
type = field.getType();
annotations = field.getAnnotations();
genericType = field.getGenericType();
- setProfiles(this.annotations);
+ setter = null;
+ profiles = createProfiles(this.annotations);
}
- public void setProfiles(Annotation[] annotations) {
+ private static String[] createProfiles(Annotation[] annotations) {
if (annotations != null) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().equals(NoBinding.class)) {
NoBinding as = ((NoBinding) annotation);
- profiles = as.value();
+ return as.value();
}
}
}
+ return null;
}
public void setValue(Object instance, Object value) {
View
8 framework/src/play/data/binding/Binder.java
@@ -48,15 +48,11 @@
supportedTypes.put(clazz, typeBinder);
}
- static Map<Class<?>, BeanWrapper> beanwrappers = new HashMap<Class<?>, BeanWrapper>();
static BeanWrapper getBeanWrapper(Class<?> clazz) {
- if (!beanwrappers.containsKey(clazz)) {
- BeanWrapper beanwrapper = BeanWrapper.forClass(clazz);
- beanwrappers.put(clazz, beanwrapper);
- }
- return beanwrappers.get(clazz);
+ return BeanWrapper.forClass(clazz);
}
+
public final static Object MISSING = new Object();
public final static Object NO_BINDING = new Object();
Something went wrong with that request. Please try again.