You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bval.apache.org by rm...@apache.org on 2013/08/16 08:57:44 UTC

svn commit: r1514596 - in /bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303: ConstraintAnnotationAttributes.java xml/AnnotationProxy.java xml/AnnotationProxyBuilder.java xml/ValidationParser.java

Author: rmannibucau
Date: Fri Aug 16 06:57:43 2013
New Revision: 1514596

URL: http://svn.apache.org/r1514596
Log:
caching built in constraint methods + caching xsd schema

Modified:
    bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintAnnotationAttributes.java
    bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxy.java
    bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxyBuilder.java
    bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/ValidationParser.java

Modified: bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintAnnotationAttributes.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintAnnotationAttributes.java?rev=1514596&r1=1514595&r2=1514596&view=diff
==============================================================================
--- bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintAnnotationAttributes.java (original)
+++ bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/ConstraintAnnotationAttributes.java Fri Aug 16 06:57:43 2013
@@ -30,6 +30,8 @@ import java.lang.reflect.Type;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * Defines the well-known attributes of {@link Constraint} annotations.
@@ -88,8 +90,6 @@ public enum ConstraintAnnotationAttribut
 
     /**
      * Get the expected type of the represented attribute.
-     * 
-     * @return Class<?>
      */
     public Type getType() {
         return type;
@@ -137,7 +137,18 @@ public enum ConstraintAnnotationAttribut
         return new Worker<C>(clazz);
     }
 
+    // this is static but related to Worker
+    private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Method>> METHOD_BY_NAME_AND_CLASS = new ConcurrentHashMap<Class<?>, ConcurrentMap<String, Method>>();
+    private static final Method NULL_METHOD;
+    static {
+        try {
+            NULL_METHOD = Object.class.getMethod("hashCode"); // whatever, the only constraint here is to not use a constraint method, this value is used to cache null
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException("Impossible normally");
+        }
+    }
     public class Worker<C extends Annotation> {
+
         public final Method method;
         public final Object defaultValue;
         private RuntimeException error;
@@ -149,8 +160,8 @@ public enum ConstraintAnnotationAttribut
         Worker(final Class<C> constraintType) {
             Object _defaultValue = null;
             try {
-                method = Reflection.INSTANCE.getPublicMethod(constraintType, attributeName);
-                if (method == null) {
+                method = findMethod(constraintType, attributeName);
+                if (method == null || method == NULL_METHOD) {
                     error = new ConstraintDefinitionException("Annotation " + constraintType + " has no " + attributeName + " method");
                     return;
                 }
@@ -171,6 +182,32 @@ public enum ConstraintAnnotationAttribut
             }
         }
 
+        private Method findMethod(final Class<C> constraintType, final String attributeName) {
+            ConcurrentMap<String, Method> cache = METHOD_BY_NAME_AND_CLASS.get(constraintType);
+            if (cache == null) {
+                cache = new ConcurrentHashMap<String, Method>();
+                final ConcurrentMap<String, Method> old = METHOD_BY_NAME_AND_CLASS.putIfAbsent(constraintType, cache);
+                if (old != null) {
+                    cache = old;
+                }
+            }
+
+            final Method found = cache.get(attributeName);
+            if (found != null) {
+                return found;
+            }
+            final Method m = Reflection.INSTANCE.getPublicMethod(constraintType, attributeName);
+            if (m == null) {
+                cache.putIfAbsent(attributeName, NULL_METHOD);
+                return null;
+            }
+            final Method oldMtd = cache.putIfAbsent(attributeName, m);
+            if (oldMtd != null) {
+                return oldMtd;
+            }
+            return m;
+        }
+
         public boolean isValid() {
             return error == null;
         }

Modified: bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxy.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxy.java?rev=1514596&r1=1514595&r2=1514596&view=diff
==============================================================================
--- bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxy.java (original)
+++ bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxy.java Fri Aug 16 06:57:43 2013
@@ -16,8 +16,6 @@
  */
 package org.apache.bval.jsr303.xml;
 
-import org.apache.bval.util.reflection.Reflection;
-
 import javax.validation.Valid;
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
@@ -54,10 +52,9 @@ class AnnotationProxy implements Annotat
     }
 
     private <A extends Annotation> Map<String, Object> getAnnotationValues(AnnotationProxyBuilder<A> descriptor) {
-        Map<String, Object> result = new HashMap<String, Object>();
+        final Map<String, Object> result = new HashMap<String, Object>();
         int processedValuesFromDescriptor = 0;
-        final Method[] declaredMethods = Reflection.INSTANCE.getDeclaredMethods(annotationType);
-        for (Method m : declaredMethods) {
+        for (final Method m : descriptor.getMethods()) {
             if (descriptor.contains(m.getName())) {
                 result.put(m.getName(), descriptor.getValue(m.getName()));
                 processedValuesFromDescriptor++;

Modified: bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxyBuilder.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxyBuilder.java?rev=1514596&r1=1514595&r2=1514596&view=diff
==============================================================================
--- bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxyBuilder.java (original)
+++ bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/AnnotationProxyBuilder.java Fri Aug 16 06:57:43 2013
@@ -33,6 +33,8 @@ import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * Description: Holds the information and creates an annotation proxy during xml
@@ -41,16 +43,32 @@ import java.util.Map;
 // TODO move this guy up to org.apache.bval.jsr303 or
 // org.apache.bval.jsr303.model
 final public class AnnotationProxyBuilder<A extends Annotation> {
+    private static final ConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new ConcurrentHashMap<Class<?>, Method[]>();
+
     private final Class<A> type;
     private final Map<String, Object> elements = new HashMap<String, Object>();
+    private final Method[] methods;
 
     /**
      * Create a new AnnotationProxyBuilder instance.
      *
      * @param annotationType
      */
-    public AnnotationProxyBuilder(Class<A> annotationType) {
+    public AnnotationProxyBuilder(final Class<A> annotationType) {
         this.type = annotationType;
+        if (annotationType.getName().startsWith("javax.validation.constraints.")) { // cache built-in constraints only to avoid mem leaks
+            Method[] mtd = METHODS_CACHE.get(annotationType);
+            if (mtd == null) {
+                final Method[] value = Reflection.INSTANCE.getDeclaredMethods(type);
+                mtd = METHODS_CACHE.putIfAbsent(annotationType, value);
+                if (mtd == null) {
+                    mtd = value;
+                }
+            }
+            this.methods = mtd;
+        } else {
+            this.methods = Reflection.INSTANCE.getDeclaredMethods(type);
+        }
     }
 
     /**
@@ -76,7 +94,6 @@ final public class AnnotationProxyBuilde
     public AnnotationProxyBuilder(A annot) {
         this((Class<A>) annot.annotationType());
         // Obtain the "elements" of the annotation
-        final Method[] methods = Reflection.INSTANCE.getDeclaredMethods(annot.annotationType());
         for (Method m : methods) {
             if (!m.isAccessible()) {
                 m.setAccessible(true);
@@ -95,6 +112,10 @@ final public class AnnotationProxyBuilde
         }
     }
 
+    public Method[] getMethods() {
+        return methods;
+    }
+
     /**
      * Add an element to the configuration.
      *

Modified: bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/ValidationParser.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/ValidationParser.java?rev=1514596&r1=1514595&r2=1514596&view=diff
==============================================================================
--- bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/ValidationParser.java (original)
+++ bval/branches/bval-11/bval-jsr303/src/main/java/org/apache/bval/jsr303/xml/ValidationParser.java Fri Aug 16 06:57:43 2013
@@ -53,6 +53,8 @@ import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.logging.Level;
@@ -64,9 +66,9 @@ import java.util.logging.Logger;
 @SuppressWarnings("restriction")
 public class ValidationParser implements Closeable {
     private static final String DEFAULT_VALIDATION_XML_FILE = "META-INF/validation.xml";
-    private static final String VALIDATION_CONFIGURATION_XSD =
-            "META-INF/validation-configuration-1.1.xsd";
+    private static final String VALIDATION_CONFIGURATION_XSD = "META-INF/validation-configuration-1.1.xsd";
     private static final Logger log = Logger.getLogger(ValidationParser.class.getName());
+    private static final ConcurrentMap<String, Schema> SCHEMA_CACHE = new ConcurrentHashMap<String, Schema>(1);
 
     private ValidationConfigType xmlConfig;
     private BootstrapConfigurationImpl bootstrap;
@@ -191,16 +193,16 @@ public class ValidationParser implements
         }
     }
 
-    protected static InputStream getInputStream(String path) throws IOException {
-        ClassLoader loader = Reflection.INSTANCE.getClassLoader(ValidationParser.class);
-        InputStream inputStream = loader.getResourceAsStream(path);
+    protected static InputStream getInputStream(final String path) throws IOException {
+        final ClassLoader loader = Reflection.INSTANCE.getClassLoader(ValidationParser.class);
+        final InputStream inputStream = loader.getResourceAsStream(path);
 
         if (inputStream != null) {
             // spec says: If more than one META-INF/validation.xml file
             // is found in the classpath, a ValidationException is raised.
-            Enumeration<URL> urls = loader.getResources(path);
+            final Enumeration<URL> urls = loader.getResources(path);
             if (urls.hasMoreElements()) {
-                String url = urls.nextElement().toString();
+                final String url = urls.nextElement().toString();
                 while (urls.hasMoreElements()) {
                     if (!url.equals(urls.nextElement().toString())) { // complain when first duplicate found
                         throw new ValidationException("More than one " + path + " is found in the classpath");
@@ -217,11 +219,21 @@ public class ValidationParser implements
     }
 
     static Schema getSchema(final String xsd) {
+        final Schema schema = SCHEMA_CACHE.get(xsd);
+        if (schema != null) {
+            return schema;
+        }
+
         final ClassLoader loader = Reflection.INSTANCE.getClassLoader(ValidationParser.class);
         final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
         final URL schemaUrl = loader.getResource(xsd);
         try {
-            return sf.newSchema(schemaUrl);
+            Schema s = sf.newSchema(schemaUrl);
+            final Schema old = SCHEMA_CACHE.putIfAbsent(xsd, s);
+            if (old != null) {
+                s = old;
+            }
+            return s;
         } catch (SAXException e) {
             log.log(Level.WARNING, String.format("Unable to parse schema: %s", xsd), e);
             return null;