Forward ported from 2.3-gae: FREEMARKER-80: Avoid calling synchonized 
PropertyDescriptor.getReadMethod() when getting a property in a template. Will 
see if it matters.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/ef4674e8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/ef4674e8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/ef4674e8

Branch: refs/heads/3
Commit: ef4674e84dd8802112555c456a1fdcc884f92f6c
Parents: fa92465
Author: ddekany <[email protected]>
Authored: Tue Oct 3 20:23:32 2017 +0200
Committer: ddekany <[email protected]>
Committed: Tue Oct 3 20:23:32 2017 +0200

----------------------------------------------------------------------
 .../freemarker/core/model/impl/BeanModel.java   | 20 ++------
 .../core/model/impl/ClassIntrospector.java      | 51 +++-----------------
 .../core/model/impl/FastPropertyDescriptor.java | 39 +++++++++++++++
 3 files changed, 50 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ef4674e8/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
index accadaf..9dbe5b6 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
@@ -19,8 +19,6 @@
 
 package org.apache.freemarker.core.model.impl;
 
-import java.beans.IndexedPropertyDescriptor;
-import java.beans.PropertyDescriptor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -180,21 +178,9 @@ public class BeanModel
         }
 
         TemplateModel resultModel = UNKNOWN;
-        if (desc instanceof PropertyDescriptor) {
-            PropertyDescriptor pd = (PropertyDescriptor) desc;
-            Method readMethod = pd.getReadMethod();
-            if (readMethod != null) {
-                // Unlike in FreeMarker 2, we prefer the normal read method 
even if there's an indexed read method.
-                resultModel = wrapper.invokeMethod(object, readMethod, null);
-                // cachedModel remains null, as we don't cache these
-            } else if (desc instanceof IndexedPropertyDescriptor) {
-                // In FreeMarker 2 we have exposed such indexed properties as 
sequences, but they can't support
-                // the getCollectionSize() method, so we have discontinued 
that. People has to call the indexed read
-                // method like any other method.
-                resultModel = UNKNOWN;
-            } else {
-                throw new IllegalStateException("PropertyDescriptor.readMethod 
shouldn't be null");
-            }
+        if (desc instanceof FastPropertyDescriptor) {
+            // Unlike in FreeMarker 2, we always use the normal read method, 
and ignore the indexed read method.
+            resultModel = wrapper.invokeMethod(object, 
((FastPropertyDescriptor) desc).getReadMethod(), null);
         } else if (desc instanceof Field) {
             resultModel = wrapper.wrap(((Field) desc).get(object));
             // cachedModel remains null, as we don't cache these

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ef4674e8/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
index cc083d4..94eca36 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
@@ -206,7 +206,7 @@ class ClassIntrospector {
      * Gets the class introspection data from {@link #cache}, automatically 
creating the cache entry if it's missing.
      * 
      * @return A {@link Map} where each key is a property/method/field name 
(or a special {@link Object} key like
-     *         {@link #CONSTRUCTORS_KEY}), each value is a {@link 
PropertyDescriptor} or {@link Method} or
+     *         {@link #CONSTRUCTORS_KEY}), each value is a {@link 
FastPropertyDescriptor} or {@link Method} or
      *         {@link OverloadedMethods} or {@link Field} (but better check 
the source code...).
      */
     Map<Object, Object> get(Class<?> clazz) {
@@ -321,8 +321,7 @@ class ClassIntrospector {
             int mdsSize = mds.size();
             IdentityHashMap<Method, Void> argTypesUsedByIndexerPropReaders = 
null;
             for (int i = mdsSize - 1; i >= 0; --i) {
-                final MethodDescriptor md = mds.get(i);
-                final Method method = 
getMatchingAccessibleMethod(md.getMethod(), accessibleMethods);
+                final Method method = 
getMatchingAccessibleMethod(mds.get(i).getMethod(), accessibleMethods);
                 if (method != null && isAllowedToExpose(method)) {
                     decision.setDefaults(method);
                     if (methodAppearanceFineTuner != null) {
@@ -336,7 +335,7 @@ class ClassIntrospector {
                     }
 
                     PropertyDescriptor propDesc = 
decision.getExposeAsProperty();
-                    if (propDesc != null && 
!(introspData.get(propDesc.getName()) instanceof PropertyDescriptor)) {
+                    if (propDesc != null && 
!(introspData.get(propDesc.getName()) instanceof FastPropertyDescriptor)) {
                         addPropertyDescriptorToClassIntrospectionData(
                                 introspData, propDesc, clazz, 
accessibleMethods);
                     }
@@ -359,7 +358,7 @@ class ClassIntrospector {
                             // Already overloaded method - add new overload
                             ((OverloadedMethods) previous).addMethod(method);
                         } else if (decision.getMethodShadowsProperty()
-                                || !(previous instanceof PropertyDescriptor)) {
+                                || !(previous instanceof 
FastPropertyDescriptor)) {
                             // Simple method (this far)
                             introspData.put(methodKey, method);
                             Class<?>[] replaced = 
getArgTypesByMethod(introspData).put(method,
@@ -377,6 +376,7 @@ class ClassIntrospector {
         } // end if (exposureLevel < EXPOSE_PROPERTIES_ONLY)
     }
 
+    // TODO [FM3] As we ignore indexed property getters in FM3, this might 
could be simplified. 
     /**
      * Very similar to {@link BeanInfo#getPropertyDescriptors()}, but can deal 
with Java 8 default methods too.
      */
@@ -647,44 +647,9 @@ class ClassIntrospector {
 
     private void addPropertyDescriptorToClassIntrospectionData(Map<Object, 
Object> introspData,
             PropertyDescriptor pd, Class<?> clazz, Map<MethodSignature, 
List<Method>> accessibleMethods) {
-        if (pd instanceof IndexedPropertyDescriptor) {
-            IndexedPropertyDescriptor ipd =
-                    (IndexedPropertyDescriptor) pd;
-            Method readMethod = ipd.getIndexedReadMethod();
-            Method publicReadMethod = getMatchingAccessibleMethod(readMethod, 
accessibleMethods);
-            if (publicReadMethod != null && 
isAllowedToExpose(publicReadMethod)) {
-                try {
-                    if (readMethod != publicReadMethod) {
-                        ipd = new IndexedPropertyDescriptor(
-                                ipd.getName(), ipd.getReadMethod(),
-                                null, publicReadMethod,
-                                null);
-                    }
-                    introspData.put(ipd.getName(), ipd);
-                    getArgTypesByMethod(introspData).put(publicReadMethod, 
publicReadMethod.getParameterTypes());
-                } catch (IntrospectionException e) {
-                    LOG.warn("Failed creating a publicly-accessible property 
descriptor "
-                            + "for {} indexed property {}, read method {}",
-                            clazz.getName(), pd.getName(), publicReadMethod,
-                            e);
-                }
-            }
-        } else {
-            Method readMethod = pd.getReadMethod();
-            Method publicReadMethod = getMatchingAccessibleMethod(readMethod, 
accessibleMethods);
-            if (publicReadMethod != null && 
isAllowedToExpose(publicReadMethod)) {
-                try {
-                    if (readMethod != publicReadMethod) {
-                        pd = new PropertyDescriptor(pd.getName(), 
publicReadMethod, null);
-                    }
-                    introspData.put(pd.getName(), pd);
-                } catch (IntrospectionException e) {
-                    LOG.warn("Failed creating a publicly-accessible property 
descriptor "
-                            + "for {} property {}, read method {}",
-                            clazz.getName(), pd.getName(), publicReadMethod,
-                            e);
-                }
-            }
+        Method readMethod = getMatchingAccessibleMethod(pd.getReadMethod(), 
accessibleMethods);
+        if (readMethod != null && isAllowedToExpose(readMethod)) {
+            introspData.put(pd.getName(), new 
FastPropertyDescriptor(readMethod));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ef4674e8/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/FastPropertyDescriptor.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/FastPropertyDescriptor.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/FastPropertyDescriptor.java
new file mode 100644
index 0000000..1019ba9
--- /dev/null
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/FastPropertyDescriptor.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.freemarker.core.model.impl;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+
+/**
+ * Used instead of {@link PropertyDescriptor}, because the methods of that are 
synchronized.
+ * Note that if a property has no read method (a non-indexed an one), then we 
don't treat is as a property.
+ */
+final class FastPropertyDescriptor {
+    private final Method readMethod;
+    
+    public FastPropertyDescriptor(Method readMethod) {
+        this.readMethod = readMethod;
+    }
+
+    public Method getReadMethod() {
+        return readMethod;
+    }
+    
+}

Reply via email to