Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 0A8BB200BD6 for ; Sun, 4 Dec 2016 13:20:06 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 09097160B18; Sun, 4 Dec 2016 12:20:06 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id BB7B3160AE4 for ; Sun, 4 Dec 2016 13:20:03 +0100 (CET) Received: (qmail 30718 invoked by uid 500); 4 Dec 2016 12:20:02 -0000 Mailing-List: contact notifications-help@freemarker.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@freemarker.incubator.apache.org Delivered-To: mailing list notifications@freemarker.incubator.apache.org Received: (qmail 30709 invoked by uid 99); 4 Dec 2016 12:20:02 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd4-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 04 Dec 2016 12:20:02 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd4-us-west.apache.org (ASF Mail Server at spamd4-us-west.apache.org) with ESMTP id 3D2E7C002D for ; Sun, 4 Dec 2016 12:20:02 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd4-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -6.218 X-Spam-Level: X-Spam-Status: No, score=-6.218 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-2.999, URIBL_BLOCKED=0.001] autolearn=disabled Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd4-us-west.apache.org [10.40.0.11]) (amavisd-new, port 10024) with ESMTP id rPrz4uk6eRFB for ; Sun, 4 Dec 2016 12:19:51 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with SMTP id DE3D75F20B for ; Sun, 4 Dec 2016 12:19:49 +0000 (UTC) Received: (qmail 30618 invoked by uid 99); 4 Dec 2016 12:19:49 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 04 Dec 2016 12:19:49 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id C129AE08AB; Sun, 4 Dec 2016 12:19:48 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: ddekany@apache.org To: notifications@freemarker.incubator.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: incubator-freemarker git commit: Utilizing Java 5 generics at some places where it doesn't break backward compatibility. Replaceding freemarker.ext.util.IdentityHashMap usages with java.util.IdentityHashMap. Some internal naming cleanup. Date: Sun, 4 Dec 2016 12:19:48 +0000 (UTC) archived-at: Sun, 04 Dec 2016 12:20:06 -0000 Repository: incubator-freemarker Updated Branches: refs/heads/2.3-gae 5be880de5 -> 277956d94 Utilizing Java 5 generics at some places where it doesn't break backward compatibility. Replaceding freemarker.ext.util.IdentityHashMap usages with java.util.IdentityHashMap. Some internal naming cleanup. Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/277956d9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/277956d9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/277956d9 Branch: refs/heads/2.3-gae Commit: 277956d94a5e5972f47f24188ea1c48b13d6b70b Parents: 5be880d Author: ddekany Authored: Sat Dec 3 19:29:35 2016 +0100 Committer: ddekany Committed: Sun Dec 4 13:19:27 2016 +0100 ---------------------------------------------------------------------- src/main/java/freemarker/core/NewBI.java | 8 +- .../debug/impl/RmiDebuggedEnvironmentImpl.java | 2 +- .../freemarker/ext/beans/ArgumentTypes.java | 75 +++++---- .../java/freemarker/ext/beans/BeanModel.java | 6 +- .../java/freemarker/ext/beans/BeansWrapper.java | 87 ++++++----- .../ext/beans/BeansWrapperBuilder.java | 17 +- .../freemarker/ext/beans/ClassIntrospector.java | 156 ++++++++++--------- .../java/freemarker/ext/beans/_BeansAPI.java | 70 +++++---- .../freemarker/ext/util/IdentityHashMap.java | 9 +- .../java/freemarker/ext/util/ModelCache.java | 19 ++- .../template/DefaultObjectWrapper.java | 23 +-- .../template/DefaultObjectWrapperBuilder.java | 18 ++- .../template/ObjectWrapperAndUnwrapper.java | 2 +- .../java/freemarker/template/_TemplateAPI.java | 2 - 14 files changed, 264 insertions(+), 230 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/core/NewBI.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/NewBI.java b/src/main/java/freemarker/core/NewBI.java index c7842de..eddd823 100644 --- a/src/main/java/freemarker/core/NewBI.java +++ b/src/main/java/freemarker/core/NewBI.java @@ -21,6 +21,7 @@ package freemarker.core; import java.util.List; +import freemarker.ext.beans.BeanModel; import freemarker.ext.beans.BeansWrapper; import freemarker.template.ObjectWrapper; import freemarker.template.Template; @@ -35,8 +36,7 @@ import freemarker.template.TemplateModelException; */ class NewBI extends BuiltIn { - static final Class BEAN_MODEL_CLASS = freemarker.ext.beans.BeanModel.class; - static Class JYTHON_MODEL_CLASS; + static Class JYTHON_MODEL_CLASS; static { try { JYTHON_MODEL_CLASS = Class.forName("freemarker.ext.jython.JythonModel"); @@ -53,7 +53,7 @@ class NewBI extends BuiltIn { class ConstructorFunction implements TemplateMethodModelEx { - private final Class cl; + private final Class cl; private final Environment env; public ConstructorFunction(String classname, Environment env, Template template) throws TemplateException { @@ -63,7 +63,7 @@ class NewBI extends BuiltIn { throw new _MiscTemplateException(NewBI.this, env, "Class ", cl.getName(), " does not implement freemarker.template.TemplateModel"); } - if (BEAN_MODEL_CLASS.isAssignableFrom(cl)) { + if (BeanModel.class.isAssignableFrom(cl)) { throw new _MiscTemplateException(NewBI.this, env, "Bean Models cannot be instantiated using the ?", key, " built-in"); } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/debug/impl/RmiDebuggedEnvironmentImpl.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/debug/impl/RmiDebuggedEnvironmentImpl.java b/src/main/java/freemarker/debug/impl/RmiDebuggedEnvironmentImpl.java index 8bb1b3c..ec6e5a4 100644 --- a/src/main/java/freemarker/debug/impl/RmiDebuggedEnvironmentImpl.java +++ b/src/main/java/freemarker/debug/impl/RmiDebuggedEnvironmentImpl.java @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -38,7 +39,6 @@ import freemarker.core.Configurable; import freemarker.core.Environment; import freemarker.debug.DebugModel; import freemarker.debug.DebuggedEnvironment; -import freemarker.ext.util.IdentityHashMap; import freemarker.template.Configuration; import freemarker.template.SimpleCollection; import freemarker.template.SimpleScalar; http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/ext/beans/ArgumentTypes.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/beans/ArgumentTypes.java b/src/main/java/freemarker/ext/beans/ArgumentTypes.java index 11f1b77..e383259 100644 --- a/src/main/java/freemarker/ext/beans/ArgumentTypes.java +++ b/src/main/java/freemarker/ext/beans/ArgumentTypes.java @@ -54,7 +54,7 @@ final class ArgumentTypes { /** * The types of the arguments; for varags this contains the exploded list (not the array). */ - private final Class[] types; + private final Class[] types; private final boolean bugfixed; @@ -65,7 +65,7 @@ final class ArgumentTypes { */ ArgumentTypes(Object[] args, boolean bugfixed) { int ln = args.length; - Class[] typesTmp = new Class[ln]; + Class[] typesTmp = new Class[ln]; for (int i = 0; i < ln; ++i) { Object arg = args[i]; typesTmp[i] = arg == null @@ -109,22 +109,21 @@ final class ArgumentTypes { * {@link EmptyCallableMemberDescriptor#AMBIGUOUS_METHOD}. */ MaybeEmptyCallableMemberDescriptor getMostSpecific( - List/**/ memberDescs, boolean varArg) { - LinkedList/**/ applicables = getApplicables(memberDescs, varArg); + List memberDescs, boolean varArg) { + LinkedList applicables = getApplicables(memberDescs, varArg); if (applicables.isEmpty()) { return EmptyCallableMemberDescriptor.NO_SUCH_METHOD; } if (applicables.size() == 1) { - return (CallableMemberDescriptor) applicables.getFirst(); + return applicables.getFirst(); } - LinkedList/**/ maximals = new LinkedList(); - for (Iterator applicablesIter = applicables.iterator(); applicablesIter.hasNext(); ) { - CallableMemberDescriptor applicable = (CallableMemberDescriptor) applicablesIter.next(); + LinkedList maximals = new LinkedList(); + for (CallableMemberDescriptor applicable : applicables) { boolean lessSpecific = false; - for (Iterator maximalsIter = maximals.iterator(); + for (Iterator maximalsIter = maximals.iterator(); maximalsIter.hasNext(); ) { - CallableMemberDescriptor maximal = (CallableMemberDescriptor) maximalsIter.next(); + CallableMemberDescriptor maximal = maximalsIter.next(); final int cmpRes = compareParameterListPreferability( applicable.getParamTypes(), maximal.getParamTypes(), varArg); if (cmpRes > 0) { @@ -140,7 +139,7 @@ final class ArgumentTypes { if (maximals.size() > 1) { return EmptyCallableMemberDescriptor.AMBIGUOUS_METHOD; } - return (CallableMemberDescriptor) maximals.getFirst(); + return maximals.getFirst(); } /** @@ -174,7 +173,7 @@ final class ArgumentTypes { * @return More than 0 if the first parameter list is preferred, less then 0 if the other is preferred, * 0 if there's no decision */ - int compareParameterListPreferability(Class[] paramTypes1, Class[] paramTypes2, boolean varArg) { + int compareParameterListPreferability(Class[] paramTypes1, Class[] paramTypes2, boolean varArg) { final int argTypesLen = types.length; final int paramTypes1Len = paramTypes1.length; final int paramTypes2Len = paramTypes2.length; @@ -191,19 +190,19 @@ final class ArgumentTypes { int paramList2VeryStrongWinCnt = 0; int firstWinerParamList = 0; for (int i = 0; i < argTypesLen; i++) { - final Class paramType1 = getParamType(paramTypes1, paramTypes1Len, i, varArg); - final Class paramType2 = getParamType(paramTypes2, paramTypes2Len, i, varArg); + final Class paramType1 = getParamType(paramTypes1, paramTypes1Len, i, varArg); + final Class paramType2 = getParamType(paramTypes2, paramTypes2Len, i, varArg); final int winerParam; // 1 => paramType1; -1 => paramType2; 0 => draw if (paramType1 == paramType2) { winerParam = 0; } else { - final Class argType = types[i]; + final Class argType = types[i]; final boolean argIsNum = Number.class.isAssignableFrom(argType); final int numConvPrice1; if (argIsNum && ClassUtil.isNumerical(paramType1)) { - final Class nonPrimParamType1 = paramType1.isPrimitive() + final Class nonPrimParamType1 = paramType1.isPrimitive() ? ClassUtil.primitiveClassToBoxingClass(paramType1) : paramType1; numConvPrice1 = OverloadedNumberUtil.getArgumentConversionPrice(argType, nonPrimParamType1); } else { @@ -215,7 +214,7 @@ final class ArgumentTypes { final int numConvPrice2; if (argIsNum && ClassUtil.isNumerical(paramType2)) { - final Class nonPrimParamType2 = paramType2.isPrimitive() + final Class nonPrimParamType2 = paramType2.isPrimitive() ? ClassUtil.primitiveClassToBoxingClass(paramType2) : paramType2; numConvPrice2 = OverloadedNumberUtil.getArgumentConversionPrice(argType, nonPrimParamType2); } else { @@ -357,8 +356,8 @@ final class ArgumentTypes { // index of the varargs parameter, like if we had a single varargs argument. However, this // time we don't have an argument type, so we can only decide based on type specificity: if (argTypesLen == paramTypes1Len - 1) { - Class paramType1 = getParamType(paramTypes1, paramTypes1Len, argTypesLen, true); - Class paramType2 = getParamType(paramTypes2, paramTypes2Len, argTypesLen, true); + Class paramType1 = getParamType(paramTypes1, paramTypes1Len, argTypesLen, true); + Class paramType2 = getParamType(paramTypes2, paramTypes2Len, argTypesLen, true); if (ClassUtil.isNumerical(paramType1) && ClassUtil.isNumerical(paramType2)) { int r = OverloadedNumberUtil.compareNumberTypeSpecificity(paramType1, paramType2); if (r != 0) return r; @@ -380,8 +379,8 @@ final class ArgumentTypes { boolean paramTypes1HasAMoreSpecific = false; boolean paramTypes2HasAMoreSpecific = false; for (int i = 0; i < paramTypes1Len; ++i) { - Class paramType1 = getParamType(paramTypes1, paramTypes1Len, i, varArg); - Class paramType2 = getParamType(paramTypes2, paramTypes2Len, i, varArg); + Class paramType1 = getParamType(paramTypes1, paramTypes1Len, i, varArg); + Class paramType2 = getParamType(paramTypes2, paramTypes2Len, i, varArg); if (paramType1 != paramType2) { paramTypes1HasAMoreSpecific = paramTypes1HasAMoreSpecific @@ -408,12 +407,13 @@ final class ArgumentTypes { * @return Less-than-0, 0, or more-than-0 depending on which side is more specific. The absolute value is 1 if * the difference is only in primitive VS non-primitive, more otherwise. */ - private int compareParameterListPreferability_cmpTypeSpecificty(final Class paramType1, final Class paramType2) { + private int compareParameterListPreferability_cmpTypeSpecificty( + final Class paramType1, final Class paramType2) { // The more specific (smaller) type wins. - final Class nonPrimParamType1 = paramType1.isPrimitive() + final Class nonPrimParamType1 = paramType1.isPrimitive() ? ClassUtil.primitiveClassToBoxingClass(paramType1) : paramType1; - final Class nonPrimParamType2 = paramType2.isPrimitive() + final Class nonPrimParamType2 = paramType2.isPrimitive() ? ClassUtil.primitiveClassToBoxingClass(paramType2) : paramType2; if (nonPrimParamType1 == nonPrimParamType2) { @@ -441,7 +441,7 @@ final class ArgumentTypes { } } - private static Class getParamType(Class[] paramTypes, int paramTypesLen, int i, boolean varArg) { + private static Class getParamType(Class[] paramTypes, int paramTypesLen, int i, boolean varArg) { return varArg && i >= paramTypesLen - 1 ? paramTypes[paramTypesLen - 1].getComponentType() : paramTypes[i]; @@ -451,11 +451,10 @@ final class ArgumentTypes { * Returns all methods that are applicable to actual * parameter types represented by this ArgumentTypes object. */ - LinkedList/**/ getApplicables( - List/**/ memberDescs, boolean varArg) { - LinkedList applicables = new LinkedList(); - for (Iterator it = memberDescs.iterator(); it.hasNext(); ) { - ReflectionCallableMemberDescriptor memberDesc = (ReflectionCallableMemberDescriptor) it.next(); + LinkedList getApplicables( + List memberDescs, boolean varArg) { + LinkedList applicables = new LinkedList(); + for (ReflectionCallableMemberDescriptor memberDesc : memberDescs) { int difficulty = isApplicable(memberDesc, varArg); if (difficulty != CONVERSION_DIFFICULTY_IMPOSSIBLE) { if (difficulty == CONVERSION_DIFFICULTY_REFLECTION) { @@ -478,7 +477,7 @@ final class ArgumentTypes { * @return One of the CONVERSION_DIFFICULTY_... constants. */ private int isApplicable(ReflectionCallableMemberDescriptor memberDesc, boolean varArg) { - final Class[] paramTypes = memberDesc.getParamTypes(); + final Class[] paramTypes = memberDesc.getParamTypes(); final int cl = types.length; final int fl = paramTypes.length - (varArg ? 1 : 0); if (varArg) { @@ -502,7 +501,7 @@ final class ArgumentTypes { } } if (varArg) { - Class varArgParamType = paramTypes[fl].getComponentType(); + Class varArgParamType = paramTypes[fl].getComponentType(); for (int i = fl; i < cl; ++i) { int difficulty = isMethodInvocationConvertible(varArgParamType, types[i]); if (difficulty == CONVERSION_DIFFICULTY_IMPOSSIBLE) { @@ -530,12 +529,12 @@ final class ArgumentTypes { * * @return One of the CONVERSION_DIFFICULTY_... constants. */ - private int isMethodInvocationConvertible(final Class formal, final Class actual) { + private int isMethodInvocationConvertible(final Class formal, final Class actual) { // Check for identity or widening reference conversion if (formal.isAssignableFrom(actual) && actual != CharacterOrString.class) { return CONVERSION_DIFFICULTY_REFLECTION; } else if (bugfixed) { - final Class formalNP; + final Class formalNP; if (formal.isPrimitive()) { if (actual == Null.class) { return CONVERSION_DIFFICULTY_IMPOSSIBLE; @@ -684,7 +683,7 @@ final class ArgumentTypes { } @Override - Class[] getParamTypes() { + Class[] getParamTypes() { return callableMemberDesc.getParamTypes(); } @@ -694,10 +693,10 @@ final class ArgumentTypes { } private void convertArgsToReflectionCompatible(BeansWrapper bw, Object[] args) throws TemplateModelException { - Class[] paramTypes = callableMemberDesc.getParamTypes(); + Class[] paramTypes = callableMemberDesc.getParamTypes(); int ln = paramTypes.length; for (int i = 0; i < ln; i++) { - Class paramType = paramTypes[i]; + Class paramType = paramTypes[i]; final Object arg = args[i]; if (arg == null) continue; @@ -712,7 +711,7 @@ final class ArgumentTypes { // parameter, and that an array argument is applicable to a List parameter, so we end up with this // situation. if (paramType.isArray() && arg instanceof List) { - args[i] = bw.listToArray((List) arg, paramType, null); + args[i] = bw.listToArray((List) arg, paramType, null); } if (arg.getClass().isArray() && paramType.isAssignableFrom(List.class)) { args[i] = bw.arrayToList(arg); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/ext/beans/BeanModel.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/beans/BeanModel.java b/src/main/java/freemarker/ext/beans/BeanModel.java index 794a66b..ba3dc62 100644 --- a/src/main/java/freemarker/ext/beans/BeanModel.java +++ b/src/main/java/freemarker/ext/beans/BeanModel.java @@ -143,8 +143,8 @@ implements */ public TemplateModel get(String key) throws TemplateModelException { - Class clazz = object.getClass(); - Map classInfo = wrapper.getClassIntrospector().get(clazz); + Class clazz = object.getClass(); + Map classInfo = wrapper.getClassIntrospector().get(clazz); TemplateModel retval = null; try { @@ -206,7 +206,7 @@ implements return wrapper.getClassIntrospector().get(object.getClass()).get(ClassIntrospector.GENERIC_GET_KEY) != null; } - private TemplateModel invokeThroughDescriptor(Object desc, Map classInfo) + private TemplateModel invokeThroughDescriptor(Object desc, Map classInfo) throws IllegalAccessException, InvocationTargetException, TemplateModelException { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/ext/beans/BeansWrapper.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/beans/BeansWrapper.java b/src/main/java/freemarker/ext/beans/BeansWrapper.java index cf2d0c4..8b51238 100644 --- a/src/main/java/freemarker/ext/beans/BeansWrapper.java +++ b/src/main/java/freemarker/ext/beans/BeansWrapper.java @@ -31,6 +31,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Enumeration; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -41,7 +42,6 @@ import freemarker.core.BugException; import freemarker.core._DelayedFTLTypeDescription; import freemarker.core._DelayedShortClassName; import freemarker.core._TemplateModelException; -import freemarker.ext.util.IdentityHashMap; import freemarker.ext.util.ModelCache; import freemarker.ext.util.ModelFactory; import freemarker.ext.util.WrapperTemplateModel; @@ -94,9 +94,9 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { @Deprecated static final Object CAN_NOT_UNWRAP = ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS; - private static final Class ITERABLE_CLASS; + private static final Class ITERABLE_CLASS; static { - Class iterable; + Class iterable; try { iterable = Class.forName("java.lang.Iterable"); } catch (ClassNotFoundException e) { @@ -106,7 +106,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { ITERABLE_CLASS = iterable; } - private static final Constructor ENUMS_MODEL_CTOR = enumsModelCtor(); + private static final Constructor ENUMS_MODEL_CTOR = enumsModelCtor(); /** * At this level of exposure, all methods and properties of the @@ -296,7 +296,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { protected BeansWrapper(BeansWrapperConfiguration bwConf, boolean writeProtected, boolean finalizeConstruction) { // Backward-compatibility hack for "finetuneMethodAppearance" overrides to work: if (bwConf.getMethodAppearanceFineTuner() == null) { - Class thisClass = this.getClass(); + Class thisClass = this.getClass(); boolean overridden = false; boolean testFailed = false; try { @@ -306,7 +306,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { && thisClass != SimpleObjectWrapper.class) { try { thisClass.getDeclaredMethod("finetuneMethodAppearance", - new Class[] { Class.class, Method.class, MethodAppearanceDecision.class }); + new Class[] { Class.class, Method.class, MethodAppearanceDecision.class }); overridden = true; } catch (NoSuchMethodException e) { thisClass = thisClass.getSuperclass(); @@ -912,17 +912,17 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { private static final ModelFactory ITERATOR_FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { - return new IteratorModel((Iterator) object, (BeansWrapper) wrapper); + return new IteratorModel((Iterator) object, (BeansWrapper) wrapper); } }; private static final ModelFactory ENUMERATION_FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { - return new EnumerationModel((Enumeration) object, (BeansWrapper) wrapper); + return new EnumerationModel((Enumeration) object, (BeansWrapper) wrapper); } }; - protected ModelFactory getModelFactory(Class clazz) { + protected ModelFactory getModelFactory(Class clazz) { if (Map.class.isAssignableFrom(clazz)) { return simpleMapWrapper ? SimpleMapModel.FACTORY : MapModel.FACTORY; } @@ -983,7 +983,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { * * @see #tryUnwrapTo(TemplateModel, Class) */ - public Object unwrap(TemplateModel model, Class targetClass) + public Object unwrap(TemplateModel model, Class targetClass) throws TemplateModelException { final Object obj = tryUnwrapTo(model, targetClass); if (obj == ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS) { @@ -996,7 +996,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { /** * @since 2.3.22 */ - public Object tryUnwrapTo(TemplateModel model, Class targetClass) throws TemplateModelException { + public Object tryUnwrapTo(TemplateModel model, Class targetClass) throws TemplateModelException { return tryUnwrapTo(model, targetClass, 0); } @@ -1007,7 +1007,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { * {@link #is2321Bugfixed()} is {@code false}. * @return {@link ObjectWrapperAndUnwrapper#CANT_UNWRAP_TO_TARGET_CLASS} or the unwrapped object. */ - Object tryUnwrapTo(TemplateModel model, Class targetClass, int typeFlags) + Object tryUnwrapTo(TemplateModel model, Class targetClass, int typeFlags) throws TemplateModelException { Object res = tryUnwrapTo(model, targetClass, typeFlags, null); if ((typeFlags & TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT) != 0 @@ -1021,7 +1021,8 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { /** * See {@try #tryUnwrap(TemplateModel, Class, int, boolean)}. */ - private Object tryUnwrapTo(final TemplateModel model, Class targetClass, final int typeFlags, final Map recursionStops) + private Object tryUnwrapTo(final TemplateModel model, Class targetClass, final int typeFlags, + final Map recursionStops) throws TemplateModelException { if (model == null || model == nullModel) { return null; @@ -1249,7 +1250,8 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { * {@link ObjectWrapperAndUnwrapper#CANT_UNWRAP_TO_TARGET_CLASS} instead of throwing a * {@link TemplateModelException}. */ - Object unwrapSequenceToArray(TemplateSequenceModel seq, Class arrayClass, boolean tryOnly, Map recursionStops) + Object unwrapSequenceToArray( + TemplateSequenceModel seq, Class arrayClass, boolean tryOnly, Map recursionStops) throws TemplateModelException { if (recursionStops != null) { Object retval = recursionStops.get(seq); @@ -1257,9 +1259,9 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { return retval; } } else { - recursionStops = new IdentityHashMap(); + recursionStops = new IdentityHashMap(); } - Class componentType = arrayClass.getComponentType(); + Class componentType = arrayClass.getComponentType(); Object array = Array.newInstance(componentType, seq.size()); recursionStops.put(seq, array); try { @@ -1287,7 +1289,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { return array; } - Object listToArray(List list, Class arrayClass, Map recursionStops) + Object listToArray(List list, Class arrayClass, Map recursionStops) throws TemplateModelException { if (list instanceof SequenceAdapter) { return unwrapSequenceToArray( @@ -1302,9 +1304,9 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { return retval; } } else { - recursionStops = new IdentityHashMap(); + recursionStops = new IdentityHashMap(); } - Class componentType = arrayClass.getComponentType(); + Class componentType = arrayClass.getComponentType(); Object array = Array.newInstance(componentType, list.size()); recursionStops.put(list, array); try { @@ -1312,7 +1314,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { boolean isComponentTypeNumerical = false; // will be filled on demand boolean isComponentTypeList = false; // will be filled on demand int i = 0; - for (Iterator it = list.iterator(); it.hasNext(); ) { + for (Iterator it = list.iterator(); it.hasNext(); ) { Object listItem = it.next(); if (listItem != null && !componentType.isInstance(listItem)) { // Type conversion is needed. If we can't do it, we just let it fail at Array.set later. @@ -1333,7 +1335,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { } } else if (componentType.isArray()) { if (listItem instanceof List) { - listItem = listToArray((List) listItem, componentType, recursionStops); + listItem = listToArray((List) listItem, componentType, recursionStops); } else if (listItem instanceof TemplateSequenceModel) { listItem = unwrapSequenceToArray((TemplateSequenceModel) listItem, componentType, false, recursionStops); } @@ -1361,7 +1363,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { /** * @param array Must be an array (of either a reference or primitive type) */ - List arrayToList(Object array) throws TemplateModelException { + List arrayToList(Object array) throws TemplateModelException { if (array instanceof Object[]) { // Array of any non-primitive type. // Note that an array of non-primitive type is always instanceof Object[]. @@ -1378,7 +1380,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { * @param n Non-{@code null} * @return {@code null} if the conversion has failed. */ - static Number forceUnwrappedNumberToType(final Number n, final Class targetType, final boolean bugfixed) { + static Number forceUnwrappedNumberToType(final Number n, final Class targetType, final boolean bugfixed) { // We try to order the conditions by decreasing probability. if (targetType == n.getClass()) { return n; @@ -1516,7 +1518,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { * @param arguments The list of {@link TemplateModel}-s to pass to the constructor after unwrapping them * @return The instance created; it's not wrapped into {@link TemplateModel}. */ - public Object newInstance(Class clazz, List/**/ arguments) + public Object newInstance(Class clazz, List/**/ arguments) throws TemplateModelException { try { Object ctors = classIntrospector.get(clazz).get(ClassIntrospector.CONSTRUCTORS_KEY); @@ -1524,11 +1526,11 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { throw new TemplateModelException("Class " + clazz.getName() + " has no public constructors."); } - Constructor ctor = null; + Constructor ctor = null; Object[] objargs; if (ctors instanceof SimpleMethod) { SimpleMethod sm = (SimpleMethod) ctors; - ctor = (Constructor) sm.getMember(); + ctor = (Constructor) sm.getMember(); objargs = sm.unwrapArguments(arguments, this); try { return ctor.newInstance(objargs); @@ -1565,7 +1567,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { * * @since 2.3.20 */ - public void removeFromClassIntrospectionCache(Class clazz) { + public void removeFromClassIntrospectionCache(Class clazz) { classIntrospector.remove(clazz); } @@ -1596,7 +1598,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { */ @Deprecated protected void finetuneMethodAppearance( - Class clazz, Method m, MethodAppearanceDecision decision) { + Class clazz, Method m, MethodAppearanceDecision decision) { // left everything on its default; do nothing } @@ -1606,7 +1608,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { */ // Unused? public static void coerceBigDecimals(AccessibleObject callable, Object[] args) { - Class[] formalTypes = null; + Class[] formalTypes = null; for (int i = 0; i < args.length; ++i) { Object arg = args[i]; if (arg instanceof BigDecimal) { @@ -1614,7 +1616,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { if (callable instanceof Method) { formalTypes = ((Method) callable).getParameterTypes(); } else if (callable instanceof Constructor) { - formalTypes = ((Constructor) callable).getParameterTypes(); + formalTypes = ((Constructor) callable).getParameterTypes(); } else { throw new IllegalArgumentException("Expected method or " + " constructor; callable is " + @@ -1627,10 +1629,10 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { } /** - * Converts any {@link BigDecimal}s in the passed array to the type of - * the corresponding formal argument of the method. + * Converts any {@link BigDecimal}-s in the passed array to the type of + * the corresponding formal argument of the method via {@link #coerceBigDecimal(BigDecimal, Class)}. */ - public static void coerceBigDecimals(Class[] formalTypes, Object[] args) { + public static void coerceBigDecimals(Class[] formalTypes, Object[] args) { int typeLen = formalTypes.length; int argsLen = args.length; int min = Math.min(typeLen, argsLen); @@ -1641,7 +1643,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { } } if (argsLen > typeLen) { - Class varArgType = formalTypes[typeLen - 1]; + Class varArgType = formalTypes[typeLen - 1]; for (int i = typeLen; i < argsLen; ++i) { Object arg = args[i]; if (arg instanceof BigDecimal) { @@ -1651,7 +1653,12 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { } } - public static Object coerceBigDecimal(BigDecimal bd, Class formalType) { + /** + * Converts {@link BigDecimal} to the class given in the {@code formalType} argument if that's a known numerical + * type, returns the {@link BigDecimal} as is otherwise. Overflow and precision loss are possible, similarly as + * with casting in Java. + */ + public static Object coerceBigDecimal(BigDecimal bd, Class formalType) { // int is expected in most situations, so we check it first if (formalType == int.class || formalType == Integer.class) { return Integer.valueOf(bd.intValue()); @@ -1774,19 +1781,17 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { } /** - * Used for - * {@link MethodAppearanceFineTuner#process} - * as input parameter; see there. + * Used for {@link MethodAppearanceFineTuner#process} as input parameter; see there. */ static public final class MethodAppearanceDecisionInput { private Method method; - private Class containingClass; + private Class containingClass; void setMethod(Method method) { this.method = method; } - void setContainingClass(Class containingClass) { + void setContainingClass(Class containingClass) { this.containingClass = containingClass; } @@ -1794,7 +1799,7 @@ public class BeansWrapper implements RichObjectWrapper, WriteProtectable { return method; } - public Class getContainingClass() { + public Class/**/ getContainingClass() { return containingClass; } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/ext/beans/BeansWrapperBuilder.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/beans/BeansWrapperBuilder.java b/src/main/java/freemarker/ext/beans/BeansWrapperBuilder.java index 54090b9..f8cb545 100644 --- a/src/main/java/freemarker/ext/beans/BeansWrapperBuilder.java +++ b/src/main/java/freemarker/ext/beans/BeansWrapperBuilder.java @@ -20,6 +20,7 @@ package freemarker.ext.beans; import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.util.Map; import java.util.WeakHashMap; @@ -109,11 +110,13 @@ import freemarker.template.Version; */ public class BeansWrapperBuilder extends BeansWrapperConfiguration { - private final static WeakHashMap/*>*/ - INSTANCE_CACHE = new WeakHashMap(); - private final static ReferenceQueue INSTANCE_CACHE_REF_QUEUE = new ReferenceQueue(); + private final static Map>> + INSTANCE_CACHE = new WeakHashMap< + ClassLoader, Map>>(); + private final static ReferenceQueue INSTANCE_CACHE_REF_QUEUE = new ReferenceQueue(); - private static class BeansWrapperFactory implements _BeansAPI._BeansWrapperSubclassFactory { + private static class BeansWrapperFactory + implements _BeansAPI._BeansWrapperSubclassFactory { private static final BeansWrapperFactory INSTANCE = new BeansWrapperFactory(); @@ -137,8 +140,10 @@ public class BeansWrapperBuilder extends BeansWrapperConfiguration { } } - /** For unit testing only */ - static Map getInstanceCache() { + /** + * For unit testing only + */ + static Map>> getInstanceCache() { return INSTANCE_CACHE; } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/ext/beans/ClassIntrospector.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/beans/ClassIntrospector.java b/src/main/java/freemarker/ext/beans/ClassIntrospector.java index 6ccd872..c852636 100644 --- a/src/main/java/freemarker/ext/beans/ClassIntrospector.java +++ b/src/main/java/freemarker/ext/beans/ClassIntrospector.java @@ -41,6 +41,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -120,8 +121,11 @@ class ClassIntrospector { // ----------------------------------------------------------------------------------------------------------------- // Introspection info Map keys: - private static final Object ARGTYPES_KEY = new Object(); + /** Key in the class info Map to the Map that maps method to argument type arrays */ + private static final Object ARG_TYPES_BY_METHOD_KEY = new Object(); + /** Key in the class info Map to the object that represents the constructors (one or multiple due to overloading) */ static final Object CONSTRUCTORS_KEY = new Object(); + /** Key in the class info Map to the get(String|Object) Method */ static final Object GENERIC_GET_KEY = new Object(); // ----------------------------------------------------------------------------------------------------------------- @@ -145,12 +149,14 @@ class ClassIntrospector { // State fields: private final Object sharedLock; - private final Map/* > */cache = new ConcurrentHashMap(0, 0.75f, 16); - private final Set/* */cacheClassNames = new HashSet(0); - private final Set/* */classIntrospectionsInProgress = new HashSet(0); + private final Map, Map> cache + = new ConcurrentHashMap, Map>(0, 0.75f, 16); + private final Set cacheClassNames = new HashSet(0); + private final Set> classIntrospectionsInProgress = new HashSet>(0); - private final List/* > */modelFactories = new LinkedList(); - private final ReferenceQueue modelFactoriesRefQueue = new ReferenceQueue(); + private final List*/>> modelFactories + = new LinkedList>(); + private final ReferenceQueue modelFactoriesRefQueue = new ReferenceQueue(); private int clearingCounter; @@ -210,15 +216,15 @@ class ClassIntrospector { * {@link #CONSTRUCTORS_KEY}), each value is a {@link PropertyDescriptor} or {@link Method} or * {@link OverloadedMethods} or {@link Field} (but better check the source code...). */ - Map get(Class clazz) { + Map get(Class clazz) { { - Map introspData = (Map) cache.get(clazz); + Map introspData = cache.get(clazz); if (introspData != null) return introspData; } String className; synchronized (sharedLock) { - Map introspData = (Map) cache.get(clazz); + Map introspData = cache.get(clazz); if (introspData != null) return introspData; className = clazz.getName(); @@ -231,7 +237,7 @@ class ClassIntrospector { // waiting for its result. try { sharedLock.wait(); - introspData = (Map) cache.get(clazz); + introspData = cache.get(clazz); } catch (InterruptedException e) { throw new RuntimeException( "Class inrospection data lookup aborded: " + e); @@ -243,7 +249,7 @@ class ClassIntrospector { classIntrospectionsInProgress.add(clazz); } try { - Map introspData = createClassIntrospectionData(clazz); + Map introspData = createClassIntrospectionData(clazz); synchronized (sharedLock) { cache.put(clazz, introspData); cacheClassNames.add(className); @@ -260,14 +266,14 @@ class ClassIntrospector { /** * Creates a {@link Map} with the content as described for the return value of {@link #get(Class)}. */ - private Map createClassIntrospectionData(Class clazz) { - final Map introspData = new HashMap(); + private Map createClassIntrospectionData(Class clazz) { + final Map introspData = new HashMap(); if (exposeFields) { addFieldsToClassIntrospectionData(introspData, clazz); } - final Map accessibleMethods = discoverAccessibleMethods(clazz); + final Map> accessibleMethods = discoverAccessibleMethods(clazz); addGenericGetToClassIntrospectionData(introspData, accessibleMethods); @@ -285,14 +291,14 @@ class ClassIntrospector { if (introspData.size() > 1) { return introspData; } else if (introspData.size() == 0) { - return Collections.EMPTY_MAP; + return Collections.emptyMap(); } else { // map.size() == 1 - Map.Entry e = (Map.Entry) introspData.entrySet().iterator().next(); + Entry e = introspData.entrySet().iterator().next(); return Collections.singletonMap(e.getKey(), e.getValue()); } } - private void addFieldsToClassIntrospectionData(Map introspData, Class clazz) + private void addFieldsToClassIntrospectionData(Map introspData, Class clazz) throws SecurityException { Field[] fields = clazz.getFields(); for (int i = 0; i < fields.length; i++) { @@ -303,7 +309,8 @@ class ClassIntrospector { } } - private void addBeanInfoToClassIntrospectionData(Map introspData, Class clazz, Map accessibleMethods) + private void addBeanInfoToClassIntrospectionData( + Map introspData, Class clazz, Map> accessibleMethods) throws IntrospectionException { BeanInfo beanInfo = Introspector.getBeanInfo(clazz); @@ -354,7 +361,7 @@ class ClassIntrospector { overloadedMethods.addMethod(method); introspData.put(methodKey, overloadedMethods); // Remove parameter type information - getArgTypes(introspData).remove(previous); + getArgTypesByMethod(introspData).remove(previous); } else if (previous instanceof OverloadedMethods) { // Already overloaded method - add new overload ((OverloadedMethods) previous).addMethod(method); @@ -362,7 +369,7 @@ class ClassIntrospector { || !(previous instanceof PropertyDescriptor)) { // Simple method (this far) introspData.put(methodKey, method); - getArgTypes(introspData).put(method, + getArgTypesByMethod(introspData).put(method, method.getParameterTypes()); } } @@ -372,8 +379,8 @@ class ClassIntrospector { } // end if (exposureLevel < EXPOSE_PROPERTIES_ONLY) } - private void addPropertyDescriptorToClassIntrospectionData(Map introspData, - PropertyDescriptor pd, Class clazz, Map accessibleMethods) { + private void addPropertyDescriptorToClassIntrospectionData(Map introspData, + PropertyDescriptor pd, Class clazz, Map> accessibleMethods) { if (pd instanceof IndexedPropertyDescriptor) { IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd; @@ -388,7 +395,7 @@ class ClassIntrospector { null); } introspData.put(ipd.getName(), ipd); - getArgTypes(introspData).put(publicReadMethod, publicReadMethod.getParameterTypes()); + getArgTypesByMethod(introspData).put(publicReadMethod, publicReadMethod.getParameterTypes()); } catch (IntrospectionException e) { LOG.warn("Failed creating a publicly-accessible " + "property descriptor for " + clazz.getName() + @@ -417,8 +424,8 @@ class ClassIntrospector { } } - private void addGenericGetToClassIntrospectionData(Map introspData, - Map accessibleMethods) { + private void addGenericGetToClassIntrospectionData(Map introspData, + Map> accessibleMethods) { Method genericGet = getFirstAccessibleMethod( MethodSignature.GET_STRING_SIGNATURE, accessibleMethods); if (genericGet == null) { @@ -430,19 +437,19 @@ class ClassIntrospector { } } - private void addConstructorsToClassIntrospectionData(final Map introspData, - Class clazz) { + private void addConstructorsToClassIntrospectionData(final Map introspData, + Class clazz) { try { - Constructor[] ctors = clazz.getConstructors(); + Constructor[] ctors = clazz.getConstructors(); if (ctors.length == 1) { - Constructor ctor = ctors[0]; + Constructor ctor = ctors[0]; introspData.put(CONSTRUCTORS_KEY, new SimpleMethod(ctor, ctor.getParameterTypes())); } else if (ctors.length > 1) { - OverloadedMethods ctorMap = new OverloadedMethods(bugfixed); + OverloadedMethods overloadedCtors = new OverloadedMethods(bugfixed); for (int i = 0; i < ctors.length; i++) { - ctorMap.addConstructor(ctors[i]); + overloadedCtors.addConstructor(ctors[i]); } - introspData.put(CONSTRUCTORS_KEY, ctorMap); + introspData.put(CONSTRUCTORS_KEY, overloadedCtors); } } catch (SecurityException e) { LOG.warn("Can't discover constructors for class " + clazz.getName(), e); @@ -454,13 +461,13 @@ class ClassIntrospector { * class is not public, retrieves methods with same signature as its public methods from public superclasses and * interfaces. Basically upcasts every method to the nearest accessible method. */ - private static Map discoverAccessibleMethods(Class clazz) { - Map accessibles = new HashMap(); + private static Map> discoverAccessibleMethods(Class clazz) { + Map> accessibles = new HashMap>(); discoverAccessibleMethods(clazz, accessibles); return accessibles; } - private static void discoverAccessibleMethods(Class clazz, Map accessibles) { + private static void discoverAccessibleMethods(Class clazz, Map> accessibles) { if (Modifier.isPublic(clazz.getModifiers())) { try { Method[] methods = clazz.getMethods(); @@ -478,9 +485,10 @@ class ClassIntrospector { // public interface I { T m(); } // public class C implements I { Integer m() { return 42; } } // C.class will have both "Object m()" and "Integer m()" methods. - List methodList = (List) accessibles.get(sig); + List methodList = accessibles.get(sig); if (methodList == null) { - methodList = new LinkedList(); + // TODO Collection.singletonList is more efficient, though read only. + methodList = new LinkedList(); accessibles.put(sig, methodList); } methodList.add(method); @@ -494,27 +502,26 @@ class ClassIntrospector { } } - Class[] interfaces = clazz.getInterfaces(); + Class[] interfaces = clazz.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { discoverAccessibleMethods(interfaces[i], accessibles); } - Class superclass = clazz.getSuperclass(); + Class superclass = clazz.getSuperclass(); if (superclass != null) { discoverAccessibleMethods(superclass, accessibles); } } - private static Method getMatchingAccessibleMethod(Method m, Map accessibles) { + private static Method getMatchingAccessibleMethod(Method m, Map> accessibles) { if (m == null) { return null; } MethodSignature sig = new MethodSignature(m); - List l = (List) accessibles.get(sig); - if (l == null) { + List ams = accessibles.get(sig); + if (ams == null) { return null; } - for (Iterator iterator = l.iterator(); iterator.hasNext(); ) { - Method am = (Method) iterator.next(); + for (Method am : ams) { if (am.getReturnType() == m.getReturnType()) { return am; } @@ -522,12 +529,12 @@ class ClassIntrospector { return null; } - private static Method getFirstAccessibleMethod(MethodSignature sig, Map accessibles) { - List l = (List) accessibles.get(sig); - if (l == null || l.isEmpty()) { + private static Method getFirstAccessibleMethod(MethodSignature sig, Map> accessibles) { + List ams = accessibles.get(sig); + if (ams == null || ams.isEmpty()) { return null; } - return (Method) l.iterator().next(); + return ams.get(0); } /** @@ -541,11 +548,12 @@ class ClassIntrospector { return exposureLevel < BeansWrapper.EXPOSE_SAFE || !UnsafeMethods.isUnsafeMethod(method); } - private static Map getArgTypes(Map classMap) { - Map argTypes = (Map) classMap.get(ARGTYPES_KEY); + private static Map[]> getArgTypesByMethod(Map classInfo) { + @SuppressWarnings("unchecked") + Map[]> argTypes = (Map[]>) classInfo.get(ARG_TYPES_BY_METHOD_KEY); if (argTypes == null) { - argTypes = new HashMap(); - classMap.put(ARGTYPES_KEY, argTypes); + argTypes = new HashMap[]>(); + classInfo.put(ARG_TYPES_BY_METHOD_KEY, argTypes); } return argTypes; } @@ -557,9 +565,9 @@ class ClassIntrospector { new MethodSignature("get", new Class[] { Object.class }); private final String name; - private final Class[] args; + private final Class[] args; - private MethodSignature(String name, Class[] args) { + private MethodSignature(String name, Class[] args) { this.name = name; this.args = args; } @@ -606,8 +614,8 @@ class ClassIntrospector { cacheClassNames.clear(); clearingCounter++; - for (Iterator it = modelFactories.iterator(); it.hasNext(); ) { - Object regedMf = ((WeakReference) it.next()).get(); + for (WeakReference regedMfREf : modelFactories) { + Object regedMf = regedMfREf.get(); if (regedMf != null) { if (regedMf instanceof ClassBasedModelFactory) { ((ClassBasedModelFactory) regedMf).clearCache(); @@ -628,14 +636,14 @@ class ClassIntrospector { * * @since 2.3.20 */ - void remove(Class clazz) { + void remove(Class clazz) { synchronized (sharedLock) { cache.remove(clazz); cacheClassNames.remove(clazz.getName()); clearingCounter++; - for (Iterator it = modelFactories.iterator(); it.hasNext(); ) { - Object regedMf = ((WeakReference) it.next()).get(); + for (WeakReference regedMfREf : modelFactories) { + Object regedMf = regedMfREf.get(); if (regedMf != null) { if (regedMf instanceof ClassBasedModelFactory) { ((ClassBasedModelFactory) regedMf).removeFromCache(clazz); @@ -688,7 +696,7 @@ class ClassIntrospector { private void registerModelFactory(Object mf) { // Note that this `synchronized (sharedLock)` is also need for the BeansWrapper constructor to work safely. synchronized (sharedLock) { - modelFactories.add(new WeakReference(mf, modelFactoriesRefQueue)); + modelFactories.add(new WeakReference(mf, modelFactoriesRefQueue)); removeClearedModelFactoryReferences(); } } @@ -703,8 +711,8 @@ class ClassIntrospector { void unregisterModelFactory(Object mf) { synchronized (sharedLock) { - for (Iterator it = modelFactories.iterator(); it.hasNext(); ) { - Object regedMf = ((Reference) it.next()).get(); + for (Iterator> it = modelFactories.iterator(); it.hasNext(); ) { + Object regedMf = it.next().get(); if (regedMf == mf) { it.remove(); } @@ -714,13 +722,13 @@ class ClassIntrospector { } private void removeClearedModelFactoryReferences() { - Reference cleardRef; + Reference cleardRef; while ((cleardRef = modelFactoriesRefQueue.poll()) != null) { synchronized (sharedLock) { - findCleardRef: for (Iterator it = modelFactories.iterator(); it.hasNext(); ) { + findClearedRef: for (Iterator> it = modelFactories.iterator(); it.hasNext(); ) { if (it.next() == cleardRef) { it.remove(); - break findCleardRef; + break findClearedRef; } } } @@ -730,20 +738,22 @@ class ClassIntrospector { // ----------------------------------------------------------------------------------------------------------------- // Extracting from introspection info: - static Class[] getArgTypes(Map classMap, AccessibleObject methodOrCtor) { - return (Class[]) ((Map) classMap.get(ARGTYPES_KEY)).get(methodOrCtor); + static Class[] getArgTypes(Map classInfo, Method method) { + @SuppressWarnings("unchecked") + Map[]> argTypesByMethod = (Map[]>) classInfo.get(ARG_TYPES_BY_METHOD_KEY); + return argTypesByMethod.get(method); } /** * Returns the number of introspected methods/properties that should be available via the TemplateHashModel * interface. */ - int keyCount(Class clazz) { - Map map = get(clazz); + int keyCount(Class clazz) { + Map map = get(clazz); int count = map.size(); if (map.containsKey(CONSTRUCTORS_KEY)) count--; if (map.containsKey(GENERIC_GET_KEY)) count--; - if (map.containsKey(ARGTYPES_KEY)) count--; + if (map.containsKey(ARG_TYPES_BY_METHOD_KEY)) count--; return count; } @@ -751,11 +761,11 @@ class ClassIntrospector { * Returns the Set of names of introspected methods/properties that should be available via the TemplateHashModel * interface. */ - Set keySet(Class clazz) { - Set set = new HashSet(get(clazz).keySet()); + Set keySet(Class clazz) { + Set set = new HashSet(get(clazz).keySet()); set.remove(CONSTRUCTORS_KEY); set.remove(GENERIC_GET_KEY); - set.remove(ARGTYPES_KEY); + set.remove(ARG_TYPES_BY_METHOD_KEY); return set; } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/ext/beans/_BeansAPI.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/beans/_BeansAPI.java b/src/main/java/freemarker/ext/beans/_BeansAPI.java index f469508..a2c648d 100644 --- a/src/main/java/freemarker/ext/beans/_BeansAPI.java +++ b/src/main/java/freemarker/ext/beans/_BeansAPI.java @@ -49,7 +49,7 @@ public class _BeansAPI { return bm.getAsClassicCompatibleString(); } - public static Object newInstance(Class pClass, Object[] args, BeansWrapper bw) + public static Object newInstance(Class pClass, Object[] args, BeansWrapper bw) throws NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, TemplateModelException { return newInstance(getConstructorDescriptor(pClass, args), args, bw); @@ -60,15 +60,18 @@ public class _BeansAPI { * than what the Java reflection API provides in that it can handle overloaded constructors. This re-uses the * overloaded method selection logic of {@link BeansWrapper}. */ - private static CallableMemberDescriptor getConstructorDescriptor(Class pClass, Object[] args) throws NoSuchMethodException { + private static CallableMemberDescriptor getConstructorDescriptor(Class pClass, Object[] args) + throws NoSuchMethodException { if (args == null) args = CollectionUtils.EMPTY_OBJECT_ARRAY; final ArgumentTypes argTypes = new ArgumentTypes(args, true); - final List fixedArgMemberDescs = new ArrayList(); - final List varArgsMemberDescs = new ArrayList(); - final Constructor[] constrs = pClass.getConstructors(); + final List fixedArgMemberDescs + = new ArrayList(); + final List varArgsMemberDescs + = new ArrayList(); + final Constructor[] constrs = pClass.getConstructors(); for (int i = 0; i < constrs.length; i++) { - Constructor constr = constrs[i]; + Constructor constr = constrs[i]; ReflectionCallableMemberDescriptor memberDesc = new ReflectionCallableMemberDescriptor(constr, constr.getParameterTypes()); if (!_MethodUtil.isVarargs(constr)) { fixedArgMemberDescs.add(memberDesc); @@ -108,7 +111,7 @@ public class _BeansAPI { if (constrDesc.isVarargs()) { // We have to put all the varargs arguments into a single array argument. - final Class[] paramTypes = constrDesc.getParamTypes(); + final Class[] paramTypes = constrDesc.getParamTypes(); final int fixedArgCnt = paramTypes.length - 1; packedArgs = new Object[fixedArgCnt + 1]; @@ -116,7 +119,7 @@ public class _BeansAPI { packedArgs[i] = args[i]; } - final Class compType = paramTypes[fixedArgCnt].getComponentType(); + final Class compType = paramTypes[fixedArgCnt].getComponentType(); final int varArgCnt = args.length - fixedArgCnt; final Object varArgsArray = Array.newInstance(compType, varArgCnt); for (int i = 0; i < varArgCnt; i++) { @@ -136,47 +139,47 @@ public class _BeansAPI { * @param beansWrapperSubclassFactory Creates a new read-only object wrapper of the desired * {@link BeansWrapper} subclass. */ - public static BeansWrapper getBeansWrapperSubclassSingleton( - BeansWrapperConfiguration settings, - Map instanceCache, - ReferenceQueue instanceCacheRefQue, - _BeansWrapperSubclassFactory beansWrapperSubclassFactory) { + public static BW getBeansWrapperSubclassSingleton( + BWC settings, + Map>> instanceCache, + ReferenceQueue instanceCacheRefQue, + _BeansWrapperSubclassFactory beansWrapperSubclassFactory) { // BeansWrapper can't be cached across different Thread Context Class Loaders (TCCL), because the result of // a class name (String) to Class mappings depends on it, and the staticModels and enumModels need that. // (The ClassIntrospector doesn't have to consider the TCCL, as it only works with Class-es, not class // names.) ClassLoader tccl = Thread.currentThread().getContextClassLoader(); - Reference instanceRef; - Map/*>*/ tcclScopedCache; + Reference instanceRef; + Map> tcclScopedCache; synchronized (instanceCache) { - tcclScopedCache = (Map) instanceCache.get(tccl); + tcclScopedCache = instanceCache.get(tccl); if (tcclScopedCache == null) { - tcclScopedCache = new HashMap(); + tcclScopedCache = new HashMap>(); instanceCache.put(tccl, tcclScopedCache); instanceRef = null; } else { - instanceRef = (Reference) tcclScopedCache.get(settings); + instanceRef = tcclScopedCache.get(settings); } } - BeansWrapper instance = instanceRef != null ? (BeansWrapper) instanceRef.get() : null; + BW instance = instanceRef != null ? instanceRef.get() : null; if (instance != null) { // cache hit return instance; } // cache miss - settings = (BeansWrapperConfiguration) settings.clone(true); // prevent any aliasing issues + settings = clone(settings); // prevent any aliasing issues instance = beansWrapperSubclassFactory.create(settings); if (!instance.isWriteProtected()) { throw new BugException(); } synchronized (instanceCache) { - instanceRef = (Reference) tcclScopedCache.get(settings); - BeansWrapper concurrentInstance = instanceRef != null ? (BeansWrapper) instanceRef.get() : null; + instanceRef = tcclScopedCache.get(settings); + BW concurrentInstance = instanceRef != null ? instanceRef.get() : null; if (concurrentInstance == null) { - tcclScopedCache.put(settings, new WeakReference(instance, instanceCacheRefQue)); + tcclScopedCache.put(settings, new WeakReference(instance, instanceCacheRefQue)); } else { instance = concurrentInstance; } @@ -186,14 +189,21 @@ public class _BeansAPI { return instance; } + + @SuppressWarnings("unchecked") + private static BWC clone(BWC settings) { + return (BWC) settings.clone(true); + } - private static void removeClearedReferencesFromCache(Map instanceCache, ReferenceQueue instanceCacheRefQue) { - Reference clearedRef; + private static + void removeClearedReferencesFromCache( + Map>> instanceCache, + ReferenceQueue instanceCacheRefQue) { + Reference clearedRef; while ((clearedRef = instanceCacheRefQue.poll()) != null) { synchronized (instanceCache) { - findClearedRef: for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) { - Map tcclScopedCache = (Map) it1.next(); - for (Iterator it2 = tcclScopedCache.values().iterator(); it2.hasNext(); ) { + findClearedRef: for (Map> tcclScopedCache : instanceCache.values()) { + for (Iterator> it2 = tcclScopedCache.values().iterator(); it2.hasNext(); ) { if (it2.next() == clearedRef) { it2.remove(); break findClearedRef; @@ -207,10 +217,10 @@ public class _BeansAPI { /** * For internal use only; don't depend on this, there's no backward compatibility guarantee at all! */ - public interface _BeansWrapperSubclassFactory { + public interface _BeansWrapperSubclassFactory { /** Creates a new read-only {@link BeansWrapper}; used for {@link BeansWrapperBuilder} and such. */ - BeansWrapper create(BeansWrapperConfiguration sa); + BW create(BWC sa); } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/ext/util/IdentityHashMap.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/util/IdentityHashMap.java b/src/main/java/freemarker/ext/util/IdentityHashMap.java index 57bb9db..13e140f 100644 --- a/src/main/java/freemarker/ext/util/IdentityHashMap.java +++ b/src/main/java/freemarker/ext/util/IdentityHashMap.java @@ -30,11 +30,12 @@ import java.util.NoSuchElementException; import java.util.Set; /** - * A variant of {@link java.util.HashMap} that uses - * {@link System#identityHashCode(Object)} for hashing, and reference comparison - * instead of {@link Object#equals(Object)}. Note that this applies only to keys, - * and not to values, i.e. {@link #containsValue(Object)} still uses {@link Object#equals(Object)}. + * Was used instead of {@link java.util.IdentityHashMap} before that was added to Java itself in Java 1.4. + * + * @deprecated Use {@link java.util.IdentityHashMap} instead. */ +@SuppressWarnings("rawtypes") +@Deprecated public class IdentityHashMap extends AbstractMap implements Map, Cloneable, java.io.Serializable { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/ext/util/ModelCache.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/util/ModelCache.java b/src/main/java/freemarker/ext/util/ModelCache.java index 5a4b3ad..52ac7d1 100644 --- a/src/main/java/freemarker/ext/util/ModelCache.java +++ b/src/main/java/freemarker/ext/util/ModelCache.java @@ -23,6 +23,8 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.Map; +import java.util.IdentityHashMap; + import freemarker.template.TemplateModel; import freemarker.template.TemplateModelAdapter; @@ -32,8 +34,8 @@ import freemarker.template.TemplateModelAdapter; */ public abstract class ModelCache { private boolean useCache = false; - private Map modelCache = null; - private ReferenceQueue refQueue = null; + private Map modelCache = null; + private ReferenceQueue refQueue = null; protected ModelCache() { } @@ -46,8 +48,8 @@ public abstract class ModelCache { public synchronized void setUseCache(boolean useCache) { this.useCache = useCache; if (useCache) { - modelCache = new IdentityHashMap(); - refQueue = new ReferenceQueue(); + modelCache = new IdentityHashMap(); + refQueue = new ReferenceQueue(); } else { modelCache = null; refQueue = null; @@ -97,7 +99,7 @@ public abstract class ModelCache { // duplicate wrapper creation. However, this has no harmful side-effects and // is a lesser performance hit. synchronized (modelCache) { - ref = (ModelReference) modelCache.get(object); + ref = modelCache.get(object); } if (ref != null) @@ -111,8 +113,9 @@ public abstract class ModelCache { // Remove cleared references for (; ; ) { ModelReference queuedRef = (ModelReference) refQueue.poll(); - if (queuedRef == null) + if (queuedRef == null) { break; + } modelCache.remove(queuedRef.object); } // Register new reference @@ -125,10 +128,10 @@ public abstract class ModelCache { * When it gets cleared (that is, the model became unreachable) * it will remove itself from the model cache. */ - private static final class ModelReference extends SoftReference { + private static final class ModelReference extends SoftReference { Object object; - ModelReference(TemplateModel ref, Object object, ReferenceQueue refQueue) { + ModelReference(TemplateModel ref, Object object, ReferenceQueue refQueue) { super(ref, refQueue); this.object = object; } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/template/DefaultObjectWrapper.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/template/DefaultObjectWrapper.java b/src/main/java/freemarker/template/DefaultObjectWrapper.java index b2f5820..323e1dd 100644 --- a/src/main/java/freemarker/template/DefaultObjectWrapper.java +++ b/src/main/java/freemarker/template/DefaultObjectWrapper.java @@ -61,7 +61,7 @@ public class DefaultObjectWrapper extends freemarker.ext.beans.BeansWrapper { @Deprecated static final DefaultObjectWrapper instance = new DefaultObjectWrapper(); - static final private Class JYTHON_OBJ_CLASS; + static final private Class JYTHON_OBJ_CLASS; static final private ObjectWrapper JYTHON_WRAPPER; @@ -133,7 +133,7 @@ public class DefaultObjectWrapper extends freemarker.ext.beans.BeansWrapper { } static { - Class cl; + Class cl; ObjectWrapper ow; try { cl = Class.forName("org.python.core.PyObject"); @@ -191,7 +191,7 @@ public class DefaultObjectWrapper extends freemarker.ext.beans.BeansWrapper { } return new SimpleDate((java.util.Date) obj, getDefaultDateType()); } - final Class objClass = obj.getClass(); + final Class objClass = obj.getClass(); if (objClass.isArray()) { if (useAdaptersForContainers) { return DefaultArrayAdapter.adapt(obj, this); @@ -203,28 +203,28 @@ public class DefaultObjectWrapper extends freemarker.ext.beans.BeansWrapper { if (obj instanceof Collection) { if (useAdaptersForContainers) { if (obj instanceof List) { - return DefaultListAdapter.adapt((List) obj, this); + return DefaultListAdapter.adapt((List) obj, this); } else { return forceLegacyNonListCollections - ? (TemplateModel) new SimpleSequence((Collection) obj, this) - : (TemplateModel) DefaultNonListCollectionAdapter.adapt((Collection) obj, this); + ? (TemplateModel) new SimpleSequence((Collection) obj, this) + : (TemplateModel) DefaultNonListCollectionAdapter.adapt((Collection) obj, this); } } else { - return new SimpleSequence((Collection) obj, this); + return new SimpleSequence((Collection) obj, this); } } if (obj instanceof Map) { return useAdaptersForContainers - ? (TemplateModel) DefaultMapAdapter.adapt((Map) obj, this) - : (TemplateModel) new SimpleHash((Map) obj, this); + ? (TemplateModel) DefaultMapAdapter.adapt((Map) obj, this) + : (TemplateModel) new SimpleHash((Map) obj, this); } if (obj instanceof Boolean) { return obj.equals(Boolean.TRUE) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } if (obj instanceof Iterator) { return useAdaptersForContainers - ? (TemplateModel) DefaultIteratorAdapter.adapt((Iterator) obj, this) - : (TemplateModel) new SimpleCollection((Iterator) obj, this); + ? (TemplateModel) DefaultIteratorAdapter.adapt((Iterator) obj, this) + : (TemplateModel) new SimpleCollection((Iterator) obj, this); } if (iterableSupport && obj instanceof Iterable) { return DefaultIterableAdapter.adapt((Iterable) obj, this); @@ -261,6 +261,7 @@ public class DefaultObjectWrapper extends freemarker.ext.beans.BeansWrapper { * Converts an array to a java.util.List. */ protected Object convertArray(Object arr) { + // FM 2.4: Use Arrays.asList instead final int size = Array.getLength(arr); ArrayList list = new ArrayList(size); for (int i = 0; i < size; i++) { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/template/DefaultObjectWrapperBuilder.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/template/DefaultObjectWrapperBuilder.java b/src/main/java/freemarker/template/DefaultObjectWrapperBuilder.java index b8f89ba..7a6a027 100644 --- a/src/main/java/freemarker/template/DefaultObjectWrapperBuilder.java +++ b/src/main/java/freemarker/template/DefaultObjectWrapperBuilder.java @@ -20,11 +20,11 @@ package freemarker.template; import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.Map; import java.util.WeakHashMap; -import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.BeansWrapperBuilder; -import freemarker.ext.beans.BeansWrapperConfiguration; import freemarker.ext.beans._BeansAPI; /** @@ -38,9 +38,11 @@ import freemarker.ext.beans._BeansAPI; */ public class DefaultObjectWrapperBuilder extends DefaultObjectWrapperConfiguration { - private final static WeakHashMap/*>*/ - INSTANCE_CACHE = new WeakHashMap(); - private final static ReferenceQueue INSTANCE_CACHE_REF_QUEUE = new ReferenceQueue(); + private final static Map>> + INSTANCE_CACHE = new WeakHashMap< + ClassLoader, Map>>(); + private final static ReferenceQueue INSTANCE_CACHE_REF_QUEUE + = new ReferenceQueue(); /** * Creates a builder that creates a {@link DefaultObjectWrapper} with the given {@code incompatibleImprovements}; @@ -63,16 +65,16 @@ public class DefaultObjectWrapperBuilder extends DefaultObjectWrapperConfigurati * a singleton that is also in use elsewhere. */ public DefaultObjectWrapper build() { - return (DefaultObjectWrapper) _BeansAPI.getBeansWrapperSubclassSingleton( + return _BeansAPI.getBeansWrapperSubclassSingleton( this, INSTANCE_CACHE, INSTANCE_CACHE_REF_QUEUE, DefaultObjectWrapperFactory.INSTANCE); } private static class DefaultObjectWrapperFactory - implements _BeansAPI._BeansWrapperSubclassFactory { + implements _BeansAPI._BeansWrapperSubclassFactory { private static final DefaultObjectWrapperFactory INSTANCE = new DefaultObjectWrapperFactory(); - public BeansWrapper create(BeansWrapperConfiguration bwConf) { + public DefaultObjectWrapper create(DefaultObjectWrapperConfiguration bwConf) { return new DefaultObjectWrapper(bwConf, true); } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/template/ObjectWrapperAndUnwrapper.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/template/ObjectWrapperAndUnwrapper.java b/src/main/java/freemarker/template/ObjectWrapperAndUnwrapper.java index b48fa5f..7ec4461 100644 --- a/src/main/java/freemarker/template/ObjectWrapperAndUnwrapper.java +++ b/src/main/java/freemarker/template/ObjectWrapperAndUnwrapper.java @@ -87,6 +87,6 @@ public interface ObjectWrapperAndUnwrapper extends ObjectWrapper { * * @since 2.3.22 */ - Object tryUnwrapTo(TemplateModel tm, Class targetClass) throws TemplateModelException; + Object tryUnwrapTo(TemplateModel tm, Class targetClass) throws TemplateModelException; } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/277956d9/src/main/java/freemarker/template/_TemplateAPI.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/template/_TemplateAPI.java b/src/main/java/freemarker/template/_TemplateAPI.java index 0fc702a..c55a113 100644 --- a/src/main/java/freemarker/template/_TemplateAPI.java +++ b/src/main/java/freemarker/template/_TemplateAPI.java @@ -19,8 +19,6 @@ package freemarker.template; -import java.util.List; -import java.util.Map; import java.util.Set; import freemarker.cache.CacheStorage;