From 00094eec52dd8cb19664aa31c6ab70c47ec4766d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B4=AA=E6=9D=A5?= Date: Sat, 5 Oct 2024 11:16:40 +0800 Subject: [PATCH 1/2] fix UNICODE_CHARACTER_CLASS flag not supported --- .../jinjava/lib/filter/WordCountFilter.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/WordCountFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/WordCountFilter.java index 9c504185f..2b3472499 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/WordCountFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/WordCountFilter.java @@ -25,6 +25,20 @@ ) public class WordCountFilter implements Filter { + private static Pattern WORD_RE = Pattern.compile( + "\\w+", Pattern.MULTILINE + ); + + static { + try { + WORD_RE = Pattern.compile( + "\\w+", + Pattern.UNICODE_CHARACTER_CLASS | Pattern.MULTILINE + ); + } catch (Throwable e) { + } + } + @Override public String getName() { return "wordcount"; @@ -43,8 +57,4 @@ public Object filter(Object var, JinjavaInterpreter interpreter, String... args) return Integer.valueOf(count); } - private static final Pattern WORD_RE = Pattern.compile( - "\\w+", - Pattern.UNICODE_CHARACTER_CLASS | Pattern.MULTILINE - ); } From 249aeba3a03769f93c98dd8d789aebb970eaf681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B4=AA=E6=9D=A5?= Date: Sat, 5 Oct 2024 16:25:00 +0800 Subject: [PATCH 2/2] =?UTF-8?q?android=20=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jinjava/el/android/BeanInfoUtil.java | 62 +++ .../jinjava/el/android/NameGenerator.java | 64 +++ .../jinjava/el/ext/BeanELResolver.java | 12 +- .../com/hubspot/jinjava/lib/tag/ForTag.java | 6 +- .../java/java/beans/FeatureDescriptor.java | 237 ++++++++ .../java/beans/IntrospectionException.java | 14 + src/main/java/java/beans/Introspector.java | 84 +++ src/main/java/java/beans/MethodRef.java | 75 +++ .../java/java/beans/PropertyDescriptor.java | 508 ++++++++++++++++++ src/main/java/java/beans/Transient.java | 17 + src/main/java/java/beans/TypeResolver.java | 31 ++ 11 files changed, 1099 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/hubspot/jinjava/el/android/BeanInfoUtil.java create mode 100644 src/main/java/com/hubspot/jinjava/el/android/NameGenerator.java create mode 100644 src/main/java/java/beans/FeatureDescriptor.java create mode 100644 src/main/java/java/beans/IntrospectionException.java create mode 100644 src/main/java/java/beans/Introspector.java create mode 100644 src/main/java/java/beans/MethodRef.java create mode 100644 src/main/java/java/beans/PropertyDescriptor.java create mode 100644 src/main/java/java/beans/Transient.java create mode 100644 src/main/java/java/beans/TypeResolver.java diff --git a/src/main/java/com/hubspot/jinjava/el/android/BeanInfoUtil.java b/src/main/java/com/hubspot/jinjava/el/android/BeanInfoUtil.java new file mode 100644 index 000000000..04034e481 --- /dev/null +++ b/src/main/java/com/hubspot/jinjava/el/android/BeanInfoUtil.java @@ -0,0 +1,62 @@ +package com.hubspot.jinjava.el.android; + + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public class BeanInfoUtil { + + public static List getPropertyDescriptors(Class clazz) throws IntrospectionException { + List propertyDescriptors = new ArrayList<>(); + + // 获取所有公共字段 +// Field[] fields = clazz.getDeclaredFields(); + +// for (Field field : fields) { +// if (!Modifier.isStatic(field.getModifiers())) { +// String fieldName = field.getName(); +// if (field.getType() == boolean.class) { +// PropertyDescriptor pd = new PropertyDescriptor(fieldName, clazz,"is" + NameGenerator.capitalize(fieldName), null); +// propertyDescriptors.add(pd); +// } else { +// PropertyDescriptor pd = new PropertyDescriptor(fieldName, clazz, "get" + NameGenerator.capitalize(fieldName), null); +// propertyDescriptors.add(pd); +// } +// } +// } + + // 获取所有公共方法 + Method[] methods = clazz.getMethods(); + + ArrayList addedProperties = new ArrayList<>(); + for (Method method : methods) { + String methodName = method.getName(); + if (methodName.startsWith("get") || methodName.startsWith("is")) { + String propertyName = getPropertyName(methodName); + if (propertyName != null) { + propertyName = propertyName.toLowerCase(); + PropertyDescriptor pd = new PropertyDescriptor(propertyName, clazz, methodName, null); + if (!propertyDescriptors.contains(pd)) { + propertyDescriptors.add(pd); + addedProperties.add(propertyName); + } + } + } + } +// new Throwable("addedProperties " + addedProperties).printStackTrace(); + + return propertyDescriptors; + } + + private static String getPropertyName(String methodName) { + if (methodName.startsWith("get")) { + return methodName.substring(3); + } else if (methodName.startsWith("is")) { + return methodName.substring(2); + } + return null; + } +} diff --git a/src/main/java/com/hubspot/jinjava/el/android/NameGenerator.java b/src/main/java/com/hubspot/jinjava/el/android/NameGenerator.java new file mode 100644 index 000000000..971bfaf49 --- /dev/null +++ b/src/main/java/com/hubspot/jinjava/el/android/NameGenerator.java @@ -0,0 +1,64 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package com.hubspot.jinjava.el.android; + +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Locale; +import java.util.Map; + +public class NameGenerator { + private Map valueToName = new IdentityHashMap(); + private Map nameToCount = new HashMap(); + + public NameGenerator() { + } + + public void clear() { + this.valueToName.clear(); + this.nameToCount.clear(); + } + + public static String unqualifiedClassName(Class type) { + if (type.isArray()) { + return unqualifiedClassName(type.getComponentType()) + "Array"; + } else { + String name = type.getName(); + return name.substring(name.lastIndexOf(46) + 1); + } + } + + public static String capitalize(String name) { + if (name != null && name.length() != 0) { + String var10000 = name.substring(0, 1).toUpperCase(Locale.ENGLISH); + return var10000 + name.substring(1); + } else { + return name; + } + } + + public String instanceName(Object instance) { + if (instance == null) { + return "null"; + } else if (instance instanceof Class) { + return unqualifiedClassName((Class)instance); + } else { + String result = (String)this.valueToName.get(instance); + if (result != null) { + return result; + } else { + Class type = instance.getClass(); + String className = unqualifiedClassName(type); + Integer size = (Integer)this.nameToCount.get(className); + int instanceNumber = size == null ? 0 : size + 1; + this.nameToCount.put(className, instanceNumber); + result = className + instanceNumber; + this.valueToName.put(instance, result); + return result; + } + } + } +} diff --git a/src/main/java/com/hubspot/jinjava/el/ext/BeanELResolver.java b/src/main/java/com/hubspot/jinjava/el/ext/BeanELResolver.java index a37720465..70105a636 100644 --- a/src/main/java/com/hubspot/jinjava/el/ext/BeanELResolver.java +++ b/src/main/java/com/hubspot/jinjava/el/ext/BeanELResolver.java @@ -16,14 +16,12 @@ */ package com.hubspot.jinjava.el.ext; +import com.hubspot.jinjava.el.android.BeanInfoUtil; import java.beans.FeatureDescriptor; import java.beans.IntrospectionException; -import java.beans.Introspector; import java.beans.PropertyDescriptor; -import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; + +import java.lang.reflect.*; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -66,7 +64,7 @@ protected static final class BeanProperties { public BeanProperties(Class baseClass) { PropertyDescriptor[] descriptors; try { - descriptors = Introspector.getBeanInfo(baseClass).getPropertyDescriptors(); + descriptors = BeanInfoUtil.getPropertyDescriptors(baseClass).toArray(new PropertyDescriptor[0]); } catch (IntrospectionException e) { throw new ELException(e); } @@ -236,7 +234,7 @@ public Iterator getFeatureDescriptors( if (isResolvable(base)) { final PropertyDescriptor[] properties; try { - properties = Introspector.getBeanInfo(base.getClass()).getPropertyDescriptors(); + properties = BeanInfoUtil.getPropertyDescriptors(base.getClass()).toArray(new PropertyDescriptor[0]); } catch (IntrospectionException e) { return Collections.emptyList().iterator(); } diff --git a/src/main/java/com/hubspot/jinjava/lib/tag/ForTag.java b/src/main/java/com/hubspot/jinjava/lib/tag/ForTag.java index 622c014f0..71cd6f225 100644 --- a/src/main/java/com/hubspot/jinjava/lib/tag/ForTag.java +++ b/src/main/java/com/hubspot/jinjava/lib/tag/ForTag.java @@ -21,6 +21,7 @@ import com.hubspot.jinjava.doc.annotations.JinjavaParam; import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; import com.hubspot.jinjava.doc.annotations.JinjavaTextMateSnippet; +import com.hubspot.jinjava.el.android.BeanInfoUtil; import com.hubspot.jinjava.el.ext.DeferredParsingException; import com.hubspot.jinjava.interpret.DeferredValue; import com.hubspot.jinjava.interpret.DeferredValueException; @@ -41,7 +42,6 @@ import com.hubspot.jinjava.util.HelperStringTokenizer; import com.hubspot.jinjava.util.LengthLimitingStringBuilder; import com.hubspot.jinjava.util.ObjectIterator; -import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.util.ConcurrentModificationException; import java.util.List; @@ -241,9 +241,7 @@ public String renderForCollection( interpreter.getContext().put(loopVar, entryVal); } else { try { - PropertyDescriptor[] valProps = Introspector - .getBeanInfo(val.getClass()) - .getPropertyDescriptors(); + PropertyDescriptor[] valProps = BeanInfoUtil.getPropertyDescriptors(val.getClass()).toArray(new PropertyDescriptor[0]); for (PropertyDescriptor valProp : valProps) { if (loopVar.equals(valProp.getName())) { interpreter diff --git a/src/main/java/java/beans/FeatureDescriptor.java b/src/main/java/java/beans/FeatureDescriptor.java new file mode 100644 index 000000000..538180dc1 --- /dev/null +++ b/src/main/java/java/beans/FeatureDescriptor.java @@ -0,0 +1,237 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package java.beans; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.util.*; + +public class FeatureDescriptor { + private static final String TRANSIENT = "transient"; + private Reference> classRef; + private boolean expert; + private boolean hidden; + private boolean preferred; + private String shortDescription; + private String name; + private String displayName; + private Hashtable table; + + public FeatureDescriptor() { + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDisplayName() { + return this.displayName == null ? this.getName() : this.displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public boolean isExpert() { + return this.expert; + } + + public void setExpert(boolean expert) { + this.expert = expert; + } + + public boolean isHidden() { + return this.hidden; + } + + public void setHidden(boolean hidden) { + this.hidden = hidden; + } + + public boolean isPreferred() { + return this.preferred; + } + + public void setPreferred(boolean preferred) { + this.preferred = preferred; + } + + public String getShortDescription() { + return this.shortDescription == null ? this.getDisplayName() : this.shortDescription; + } + + public void setShortDescription(String text) { + this.shortDescription = text; + } + + public void setValue(String attributeName, Object value) { + this.getTable().put(attributeName, value); + } + + public Object getValue(String attributeName) { + return this.table != null ? this.table.get(attributeName) : null; + } + + public Enumeration attributeNames() { + return this.getTable().keys(); + } + + FeatureDescriptor(FeatureDescriptor x, FeatureDescriptor y) { + this.expert = x.expert | y.expert; + this.hidden = x.hidden | y.hidden; + this.preferred = x.preferred | y.preferred; + this.name = y.name; + this.shortDescription = x.shortDescription; + if (y.shortDescription != null) { + this.shortDescription = y.shortDescription; + } + + this.displayName = x.displayName; + if (y.displayName != null) { + this.displayName = y.displayName; + } + + this.classRef = x.classRef; + if (y.classRef != null) { + this.classRef = y.classRef; + } + + this.addTable(x.table); + this.addTable(y.table); + } + + FeatureDescriptor(FeatureDescriptor old) { + this.expert = old.expert; + this.hidden = old.hidden; + this.preferred = old.preferred; + this.name = old.name; + this.shortDescription = old.shortDescription; + this.displayName = old.displayName; + this.classRef = old.classRef; + this.addTable(old.table); + } + + private void addTable(Hashtable table) { + if (table != null && !table.isEmpty()) { + this.getTable().putAll(table); + } + + } + + private Hashtable getTable() { + if (this.table == null) { + this.table = new Hashtable(); + } + + return this.table; + } + + void setTransient(Transient annotation) { + if (annotation != null && null == this.getValue("transient")) { + this.setValue("transient", annotation.value()); + } + + } + + boolean isTransient() { + Object value = this.getValue("transient"); + return value instanceof Boolean ? (Boolean)value : false; + } + + void setClass0(Class cls) { + this.classRef = getWeakReference(cls); + } + + Class getClass0() { + return this.classRef != null ? (Class)this.classRef.get() : null; + } + + static Reference getSoftReference(T object) { + return object != null ? new SoftReference(object) : null; + } + + static Reference getWeakReference(T object) { + return object != null ? new WeakReference(object) : null; + } + + static Class getReturnType(Class base, Method method) { + if (base == null) { + base = method.getDeclaringClass(); + } + return method.getReturnType(); +// return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericReturnType())); + } + + static Class[] getParameterTypes(Class base, Method method) { + if (base == null) { + base = method.getDeclaringClass(); + } +return method.getParameterTypes();/* + return Arrays.stream(method.getGenericParameterTypes()).map(new Function, Class>() { + @Override + public Class apply(Class aClass) { + TypeResolver.erase() + return null; + } + }).toArray(Class[]::new); + return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericParameterTypes()));*/ + } + + public String toString() { + StringBuilder sb = new StringBuilder(this.getClass().getName()); + sb.append("[name=").append(this.name); + appendTo(sb, "displayName", (Object)this.displayName); + appendTo(sb, "shortDescription", (Object)this.shortDescription); + appendTo(sb, "preferred", this.preferred); + appendTo(sb, "hidden", this.hidden); + appendTo(sb, "expert", this.expert); + if (this.table != null && !this.table.isEmpty()) { + sb.append("; values={"); + Iterator var2 = this.table.entrySet().iterator(); + + while(var2.hasNext()) { + Map.Entry entry = (Map.Entry)var2.next(); + sb.append((String)entry.getKey()).append("=").append(entry.getValue()).append("; "); + } + + sb.setLength(sb.length() - 2); + sb.append("}"); + } + + this.appendTo(sb); + return sb.append("]").toString(); + } + + void appendTo(StringBuilder sb) { + } + + static void appendTo(StringBuilder sb, String name, Reference reference) { + if (reference != null) { + appendTo(sb, name, reference.get()); + } + + } + + static void appendTo(StringBuilder sb, String name, Object value) { + if (value != null) { + sb.append("; ").append(name).append("=").append(value); + } + + } + + static void appendTo(StringBuilder sb, String name, boolean value) { + if (value) { + sb.append("; ").append(name); + } + + } +} diff --git a/src/main/java/java/beans/IntrospectionException.java b/src/main/java/java/beans/IntrospectionException.java new file mode 100644 index 000000000..a38fc10ec --- /dev/null +++ b/src/main/java/java/beans/IntrospectionException.java @@ -0,0 +1,14 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package java.beans; + +public class IntrospectionException extends Exception { + private static final long serialVersionUID = -3728150539969542619L; + + public IntrospectionException(String mess) { + super(mess); + } +} diff --git a/src/main/java/java/beans/Introspector.java b/src/main/java/java/beans/Introspector.java new file mode 100644 index 000000000..7b8f0635d --- /dev/null +++ b/src/main/java/java/beans/Introspector.java @@ -0,0 +1,84 @@ +package java.beans; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Iterator; + +public class Introspector { + public static String decapitalize(String name) { + if (name != null && name.length() != 0) { + if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0))) { + return name; + } else { + char[] chars = name.toCharArray(); + chars[0] = Character.toLowerCase(chars[0]); + return new String(chars); + } + } else { + return name; + } + } + + static Method findMethod(Class cls, String methodName, int argCount) { + return findMethod(cls, methodName, argCount, (Class[])null); + } + + static Method findMethod(Class cls, String methodName, int argCount, Class[] args) { + return methodName == null ? null : internalFindMethod(cls, methodName, argCount, args); + } + + private static Method internalFindMethod(Class start, String methodName, int argCount, Class[] args) { + Class cl = start; + Method method; + label62: + while(cl != null) { + Iterator var5 = Arrays.stream(cl.getMethods()).iterator(); + + boolean different; + do { + Type[] params; + do { + do { + if (!var5.hasNext()) { + cl = cl.getSuperclass(); + continue label62; + } + + method = (Method)var5.next(); + } while(!method.getName().equals(methodName)); + + params = method.getGenericParameterTypes(); + } while(params.length != argCount); + + if (args == null) { + return method; + } + + different = false; + if (argCount <= 0) { + return method; + } + +// for(int j = 0; j < argCount; ++j) { +// if (TypeResolver.erase(TypeResolver.resolveInClass(start, params[j])) != args[j]) { +// different = true; +// } +// } + } while(different); + + return method; + } + + Class[] ifcs = start.getInterfaces(); + + for(int i = 0; i < ifcs.length; ++i) { + method = internalFindMethod(ifcs[i], methodName, argCount, (Class[])null); + if (method != null) { + return method; + } + } + + return null; + } +} diff --git a/src/main/java/java/beans/MethodRef.java b/src/main/java/java/beans/MethodRef.java new file mode 100644 index 000000000..66af49f27 --- /dev/null +++ b/src/main/java/java/beans/MethodRef.java @@ -0,0 +1,75 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package java.beans; + +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +//import sun.reflect.misc.ReflectUtil; + +public final class MethodRef { + private String signature; + private SoftReference methodRef; + private WeakReference> typeRef; + + MethodRef() { + } + + void set(Method method) { + if (method == null) { + this.signature = null; + this.methodRef = null; + this.typeRef = null; + } else { + this.signature = method.toGenericString(); + this.methodRef = new SoftReference(method); + this.typeRef = new WeakReference(method.getDeclaringClass()); + } + + } + + boolean isSet() { + return this.methodRef != null; + } + + Method get() { + if (this.methodRef == null) { + return null; + } else { + Method method = (Method)this.methodRef.get(); + if (method == null) { + method = find((Class)this.typeRef.get(), this.signature); + if (method == null) { + this.signature = null; + this.methodRef = null; + this.typeRef = null; + return null; + } + + this.methodRef = new SoftReference(method); + } + +// return ReflectUtil.isPackageAccessible(method.getDeclaringClass()) ? method : null; + return method; + } + } + + private static Method find(Class type, String signature) { + if (type != null) { + Method[] var2 = type.getMethods(); + int var3 = var2.length; + + for(int var4 = 0; var4 < var3; ++var4) { + Method method = var2[var4]; + if (type.equals(method.getDeclaringClass()) && method.toGenericString().equals(signature)) { + return method; + } + } + } + + return null; + } +} diff --git a/src/main/java/java/beans/PropertyDescriptor.java b/src/main/java/java/beans/PropertyDescriptor.java new file mode 100644 index 000000000..70508b223 --- /dev/null +++ b/src/main/java/java/beans/PropertyDescriptor.java @@ -0,0 +1,508 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package java.beans; + +import com.hubspot.jinjava.el.android.NameGenerator; + +import java.lang.ref.Reference; +import java.lang.reflect.Method; + +public class PropertyDescriptor extends FeatureDescriptor { + private Reference> propertyTypeRef; + private final MethodRef readMethodRef; + private final MethodRef writeMethodRef; + private Reference> propertyEditorClassRef; + private boolean bound; + private boolean constrained; + private String baseName; + private String writeMethodName; + private String readMethodName; + + public PropertyDescriptor(String propertyName, Class beanClass) throws IntrospectionException { + this(propertyName, beanClass, "is" + com.hubspot.jinjava.el.android.NameGenerator.capitalize(propertyName), "set" + com.hubspot.jinjava.el.android.NameGenerator.capitalize(propertyName)); + } + + public PropertyDescriptor(String propertyName, Class beanClass, String readMethodName, String writeMethodName) throws IntrospectionException { + this.readMethodRef = new MethodRef(); + this.writeMethodRef = new MethodRef(); + if (beanClass == null) { + throw new IntrospectionException("Target Bean class is null"); + } else if (propertyName != null && propertyName.length() != 0) { + if (!"".equals(readMethodName) && !"".equals(writeMethodName)) { + this.setName(propertyName); + this.setClass0(beanClass); + this.readMethodName = readMethodName; + if (readMethodName != null && this.getReadMethod() == null) { + throw new IntrospectionException("Method not found: " + readMethodName); + } else { + this.writeMethodName = writeMethodName; + if (writeMethodName != null && this.getWriteMethod() == null) { + throw new IntrospectionException("Method not found: " + writeMethodName); + } else { +// Class[] args = new Class[]{PropertyChangeListener.class}; +// this.bound = null != Introspector.findMethod(beanClass, "addPropertyChangeListener", args.length, args); + this.bound = false; + } + } + } else { + throw new IntrospectionException("read or write method name should not be the empty string"); + } + } else { + throw new IntrospectionException("bad property name"); + } + } + + public PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod) throws IntrospectionException { + this.readMethodRef = new MethodRef(); + this.writeMethodRef = new MethodRef(); + if (propertyName != null && propertyName.length() != 0) { + this.setName(propertyName); + this.setReadMethod(readMethod); + this.setWriteMethod(writeMethod); + } else { + throw new IntrospectionException("bad property name"); + } + } + + public synchronized Class getPropertyType() { + Class type = this.getPropertyType0(); + if (type == null) { + try { + type = this.findPropertyType(this.getReadMethod(), this.getWriteMethod()); + this.setPropertyType(type); + } catch (IntrospectionException var3) { + } + } + + return type; + } + + private void setPropertyType(Class type) { + this.propertyTypeRef = getWeakReference(type); + } + + private Class getPropertyType0() { + return this.propertyTypeRef != null ? (Class)this.propertyTypeRef.get() : null; + } + + private static Method getGetterMethod(Class clazz, String fieldName) { + String capitalizedFieldName = com.hubspot.jinjava.el.android.NameGenerator.capitalize(fieldName); + String methodName = "get" + capitalizedFieldName; + try { + return clazz.getMethod(methodName); + } catch (NoSuchMethodException e) { + // 尝试 isXxx() 方法 + methodName = "is" + capitalizedFieldName; + try { + return clazz.getMethod(methodName); + } catch (NoSuchMethodException ex) { + return null; + } + } + } + + private static Method getSetterMethod(Class clazz, String fieldName) { + String capitalizedFieldName = com.hubspot.jinjava.el.android.NameGenerator.capitalize(fieldName); + String methodName = "set" + capitalizedFieldName; + Class fieldType = null; + try { + fieldType = clazz.getDeclaredField(fieldName).getType(); + } catch (NoSuchFieldException e) { + return null; + } + try { + return clazz.getMethod(methodName, fieldType); + } catch (NoSuchMethodException e) { + return null; + } + } + public synchronized Method getReadMethod() { + Method readMethod = this.readMethodRef.get(); + if (readMethod == null) { + Class cls = this.getClass0(); + if (cls == null || this.readMethodName == null && !this.readMethodRef.isSet()) { + return null; + } + + String nextMethodName = "get" + this.getBaseName(); + if (this.readMethodName == null) { + Class type = this.getPropertyType0(); + if (type != Boolean.TYPE && type != null) { + this.readMethodName = nextMethodName; + } else { + this.readMethodName = "is" + this.getBaseName(); + } + } + readMethod = Introspector.findMethod(cls, this.readMethodName, 0); + if (readMethod == null && !this.readMethodName.equals(nextMethodName)) { + this.readMethodName = nextMethodName; + readMethod = Introspector.findMethod(cls, this.readMethodName, 0); + } + + try { + this.setReadMethod(readMethod); + } catch (IntrospectionException var5) { + } + } + + return readMethod; + } + + public synchronized void setReadMethod(Method readMethod) throws IntrospectionException { + this.setPropertyType(this.findPropertyType(readMethod, this.writeMethodRef.get())); + this.setReadMethod0(readMethod); + } + + private void setReadMethod0(Method readMethod) { + this.readMethodRef.set(readMethod); + if (readMethod == null) { + this.readMethodName = null; + } else { + this.setClass0(readMethod.getDeclaringClass()); + this.readMethodName = readMethod.getName(); + this.setTransient((Transient)readMethod.getAnnotation(Transient.class)); + } + } + + public synchronized Method getWriteMethod() { + Method writeMethod = this.writeMethodRef.get(); + if (writeMethod == null) { + Class cls = this.getClass0(); + if (cls == null || this.writeMethodName == null && !this.writeMethodRef.isSet()) { + return null; + } + + Class type = this.getPropertyType0(); + if (type == null) { + try { + type = this.findPropertyType(this.getReadMethod(), (Method)null); + this.setPropertyType(type); + } catch (IntrospectionException var7) { + return null; + } + } + + if (this.writeMethodName == null) { + this.writeMethodName = "set" + this.getBaseName(); + } + + Class[] args = type == null ? null : new Class[]{type}; + writeMethod = Introspector.findMethod(cls, this.writeMethodName, 1, args); + if (writeMethod != null && !writeMethod.getReturnType().equals(Void.TYPE)) { + writeMethod = null; + } + + try { + this.setWriteMethod(writeMethod); + } catch (IntrospectionException var6) { + } + } + + return writeMethod; + } + + public synchronized void setWriteMethod(Method writeMethod) throws IntrospectionException { + this.setPropertyType(this.findPropertyType(this.getReadMethod(), writeMethod)); + this.setWriteMethod0(writeMethod); + } + + private void setWriteMethod0(Method writeMethod) { + this.writeMethodRef.set(writeMethod); + if (writeMethod == null) { + this.writeMethodName = null; + } else { + this.setClass0(writeMethod.getDeclaringClass()); + this.writeMethodName = writeMethod.getName(); + this.setTransient((Transient)writeMethod.getAnnotation(Transient.class)); + } + } + + void setClass0(Class clz) { + if (this.getClass0() == null || !clz.isAssignableFrom(this.getClass0())) { + super.setClass0(clz); + } + } + + public boolean isBound() { + return this.bound; + } + + public void setBound(boolean bound) { + this.bound = bound; + } + + public boolean isConstrained() { + return this.constrained; + } + + public void setConstrained(boolean constrained) { + this.constrained = constrained; + } + + public void setPropertyEditorClass(Class propertyEditorClass) { + this.propertyEditorClassRef = getWeakReference(propertyEditorClass); + } + + public Class getPropertyEditorClass() { + return this.propertyEditorClassRef != null ? (Class)this.propertyEditorClassRef.get() : null; + } +// +// public PropertyEditor createPropertyEditor(Object bean) { +// Object editor = null; +// Class cls = this.getPropertyEditorClass(); +// if (cls != null && PropertyEditor.class.isAssignableFrom(cls) && ReflectUtil.isPackageAccessible(cls)) { +// Constructor ctor = null; +// if (bean != null) { +// try { +// ctor = cls.getConstructor(Object.class); +// } catch (Exception var7) { +// } +// } +// +// try { +// if (ctor == null) { +// editor = cls.newInstance(); +// } else { +// editor = ctor.newInstance(bean); +// } +// } catch (Exception var6) { +// } +// } +// +// return (PropertyEditor)editor; +// } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + if (obj != null && obj instanceof PropertyDescriptor) { + PropertyDescriptor other = (PropertyDescriptor)obj; + Method otherReadMethod = other.getReadMethod(); + Method otherWriteMethod = other.getWriteMethod(); + if (!this.compareMethods(this.getReadMethod(), otherReadMethod)) { + return false; + } + + if (!this.compareMethods(this.getWriteMethod(), otherWriteMethod)) { + return false; + } + + if (this.getPropertyType() == other.getPropertyType() && this.getPropertyEditorClass() == other.getPropertyEditorClass() && this.bound == other.isBound() && this.constrained == other.isConstrained() && this.writeMethodName == other.writeMethodName && this.readMethodName == other.readMethodName) { + return true; + } + } + + return false; + } + } + + boolean compareMethods(Method a, Method b) { + if (a == null != (b == null)) { + return false; + } else { + return a == null || b == null || a.equals(b); + } + } + + PropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) { + super(x, y); + this.readMethodRef = new MethodRef(); + this.writeMethodRef = new MethodRef(); + if (y.baseName != null) { + this.baseName = y.baseName; + } else { + this.baseName = x.baseName; + } + + if (y.readMethodName != null) { + this.readMethodName = y.readMethodName; + } else { + this.readMethodName = x.readMethodName; + } + + if (y.writeMethodName != null) { + this.writeMethodName = y.writeMethodName; + } else { + this.writeMethodName = x.writeMethodName; + } + + if (y.propertyTypeRef != null) { + this.propertyTypeRef = y.propertyTypeRef; + } else { + this.propertyTypeRef = x.propertyTypeRef; + } + + Method xr = x.getReadMethod(); + Method yr = y.getReadMethod(); + + try { + if (this.isAssignable(xr, yr)) { + this.setReadMethod(yr); + } else { + this.setReadMethod(xr); + } + } catch (IntrospectionException var10) { + } + + if (xr != null && yr != null && xr.getDeclaringClass() == yr.getDeclaringClass() && getReturnType(this.getClass0(), xr) == Boolean.TYPE && getReturnType(this.getClass0(), yr) == Boolean.TYPE && xr.getName().indexOf("is") == 0 && yr.getName().indexOf("get") == 0) { + try { + this.setReadMethod(xr); + } catch (IntrospectionException var9) { + } + } + + Method xw = x.getWriteMethod(); + Method yw = y.getWriteMethod(); + + try { + if (yw != null) { + this.setWriteMethod(yw); + } else { + this.setWriteMethod(xw); + } + } catch (IntrospectionException var8) { + } + + if (y.getPropertyEditorClass() != null) { + this.setPropertyEditorClass(y.getPropertyEditorClass()); + } else { + this.setPropertyEditorClass(x.getPropertyEditorClass()); + } + + this.bound = x.bound | y.bound; + this.constrained = x.constrained | y.constrained; + } + + PropertyDescriptor(PropertyDescriptor old) { + super(old); + this.readMethodRef = new MethodRef(); + this.writeMethodRef = new MethodRef(); + this.propertyTypeRef = old.propertyTypeRef; + this.readMethodRef.set(old.readMethodRef.get()); + this.writeMethodRef.set(old.writeMethodRef.get()); + this.propertyEditorClassRef = old.propertyEditorClassRef; + this.writeMethodName = old.writeMethodName; + this.readMethodName = old.readMethodName; + this.baseName = old.baseName; + this.bound = old.bound; + this.constrained = old.constrained; + } + + void updateGenericsFor(Class type) { + this.setClass0(type); + + try { + this.setPropertyType(this.findPropertyType(this.readMethodRef.get(), this.writeMethodRef.get())); + } catch (IntrospectionException var3) { + this.setPropertyType((Class)null); + } + + } + + private Class findPropertyType(Method readMethod, Method writeMethod) throws IntrospectionException { + Class propertyType = null; + + try { + Class[] params; + if (readMethod != null) { + params = getParameterTypes(this.getClass0(), readMethod); + if (params.length != 0) { + throw new IntrospectionException("bad read method arg count: " + readMethod); + } + + propertyType = getReturnType(this.getClass0(), readMethod); + if (propertyType == Void.TYPE) { + throw new IntrospectionException("read method " + readMethod.getName() + " returns void"); + } + } + + if (writeMethod != null) { + params = getParameterTypes(this.getClass0(), writeMethod); + if (params.length != 1) { + throw new IntrospectionException("bad write method arg count: " + writeMethod); + } + + if (propertyType != null && !params[0].isAssignableFrom(propertyType)) { + throw new IntrospectionException("type mismatch between read and write methods"); + } + + propertyType = params[0]; + } + + return propertyType; + } catch (IntrospectionException var5) { + throw var5; + } + } + + public int hashCode() { + int result = 7; + result = 37 * result + (this.getPropertyType() == null ? 0 : this.getPropertyType().hashCode()); + result = 37 * result + (this.getReadMethod() == null ? 0 : this.getReadMethod().hashCode()); + result = 37 * result + (this.getWriteMethod() == null ? 0 : this.getWriteMethod().hashCode()); + result = 37 * result + (this.getPropertyEditorClass() == null ? 0 : this.getPropertyEditorClass().hashCode()); + result = 37 * result + (this.writeMethodName == null ? 0 : this.writeMethodName.hashCode()); + result = 37 * result + (this.readMethodName == null ? 0 : this.readMethodName.hashCode()); + result = 37 * result + this.getName().hashCode(); + result = 37 * result + (!this.bound ? 0 : 1); + result = 37 * result + (!this.constrained ? 0 : 1); + return result; + } + + String getBaseName() { + if (this.baseName == null) { + this.baseName = NameGenerator.capitalize(this.getName()); + } + + return this.baseName; + } + + void appendTo(StringBuilder sb) { + appendTo(sb, "bound", this.bound); + appendTo(sb, "constrained", this.constrained); + appendTo(sb, "propertyEditorClass", this.propertyEditorClassRef); + appendTo(sb, "propertyType", this.propertyTypeRef); + appendTo(sb, "readMethod", this.readMethodRef.get()); + appendTo(sb, "writeMethod", this.writeMethodRef.get()); + } + + boolean isAssignable(Method m1, Method m2) { + if (m1 == null) { + return true; + } else if (m2 == null) { + return false; + } else if (!m1.getName().equals(m2.getName())) { + return true; + } else { + Class type1 = m1.getDeclaringClass(); + Class type2 = m2.getDeclaringClass(); + if (!type1.isAssignableFrom(type2)) { + return false; + } else { + type1 = getReturnType(this.getClass0(), m1); + type2 = getReturnType(this.getClass0(), m2); + if (!type1.isAssignableFrom(type2)) { + return false; + } else { + Class[] args1 = getParameterTypes(this.getClass0(), m1); + Class[] args2 = getParameterTypes(this.getClass0(), m2); + if (args1.length != args2.length) { + return true; + } else { + for(int i = 0; i < args1.length; ++i) { + if (!args1[i].isAssignableFrom(args2[i])) { + return false; + } + } + + return true; + } + } + } + } + } +} diff --git a/src/main/java/java/beans/Transient.java b/src/main/java/java/beans/Transient.java new file mode 100644 index 000000000..2847d5beb --- /dev/null +++ b/src/main/java/java/beans/Transient.java @@ -0,0 +1,17 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package java.beans; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Transient { + boolean value() default true; +} diff --git a/src/main/java/java/beans/TypeResolver.java b/src/main/java/java/beans/TypeResolver.java new file mode 100644 index 000000000..dccd7e4e5 --- /dev/null +++ b/src/main/java/java/beans/TypeResolver.java @@ -0,0 +1,31 @@ +package java.beans; + +import java.lang.reflect.*; + +public class TypeResolver { + + public static Class erase(Type type) { + if (type instanceof Class) { + return (Class) type; + } else if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) type; + return (Class) pt.getRawType(); + } else { + Type[] bounds; + if (type instanceof TypeVariable) { + TypeVariable tv = (TypeVariable) type; + bounds = tv.getBounds(); + return 0 < bounds.length ? erase(bounds[0]) : Object.class; + } else if (type instanceof WildcardType) { + WildcardType wt = (WildcardType) type; + bounds = wt.getUpperBounds(); + return 0 < bounds.length ? erase(bounds[0]) : Object.class; + } else if (type instanceof GenericArrayType) { + GenericArrayType gat = (GenericArrayType) type; + return Array.newInstance(erase(gat.getGenericComponentType()), 0).getClass(); + } else { + throw new IllegalArgumentException("Unknown Type kind: " + type.getClass()); + } + } + } +}