java - JRE 1.8 是否仍然是 JavaBean 规范提示 Indexed PropertyDescriptor?

标签 java javabeans introspection

这个问题看起来很尴尬,但我们在检索 javabean 的 PropertyDescriptors 时遇到了一个奇怪的行为。 下面是一段简单代码在 1.6、1.7 和 1.8 上的执行结果,编译时符合 1.6 标准。

Java 1.6 执行:

java.beans.PropertyDescriptor@4ddc1428 <- 不重要 java.beans.IndexedPropertyDescriptor@7174807e <- 是的,我有一个索引属性

Java 1.7 执行:

java.beans.PropertyDescriptor[名称=类; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()] <- 不重要 java.beans.IndexedPropertyDescriptor[名称=值; indexedPropertyType=class java.lang.String; indexedReadMethod=public java.lang.String JavaBean.getValues(int)] <- 是的,我有一个索引属性

Java 1.8 执行:

java.beans.PropertyDescriptor[名称=类; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()] <- 不重要 java.beans.PropertyDescriptor[名称=值; propertyType=接口(interface)java.util.List; readMethod=public java.util.List JavaBean.getValues()] <- 哎哟!这不再是索引属性!

为什么变了?

javabean 规范说明了如何使用索引访问属性。并没有说必须使用数组作为索引属性的容器。我错了吗?

我阅读了规范,第 8.3.3 章讨论了索引属性的设计模式,而不是严格的规则。

如何在不重构所有应用程序的情况下使以前的行为再次出现? < 旧应用程序、大量代码需要修改等...

感谢您的回答,

JavaBean 类

import java.util.ArrayList;  
import java.util.List;  


public class JavaBean {  


  private List<String> values = new ArrayList<String>();  


  public String getValues(int index) {  
  return this.values.get(index);  
  }  


  public List<String> getValues() {  
  return this.values;  
  }  
}  

主类

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;

public class Test {
    public static void main(String[] args) throws IntrospectionException {
         PropertyDescriptor[] descs =
         Introspector.getBeanInfo(JavaBean.class).getPropertyDescriptors();
         for (PropertyDescriptor pd : descs) {
         System.out.println(pd);
         }
    }
}

最佳答案

来自 JavaBeans 1.01 规范,第 7.2 节“索引属性”:

A component may also expose an indexed property as a single array value.

第 8.3 节描述了设计模式 introspection在没有显式 BeanInfo 的情况下识别。第 8.3.3 节说只有数组属性会触发索引属性的自动识别。

你在技术上是正确的;使用数组不是强制性的。但如果你不这样做,规范说你必须提供你自己的 BeanInfo 来将该属性公开为索引属性。

所以您的问题的答案是:是的,Java 1.8 符合 JavaBean 规范。

我不确定为什么支持 List 属性。也许 future 的 JavaBeans 规范会支持它们,但现在已经被撤销。

关于您的最后一个问题:我认为您必须为每个具有 List 属性的类创建一个 BeanInfo 类。我希望您可以创建一个通用父类(super class)以使其更容易,例如:

public abstract class ListRecognizingBeanInfo
extends SimpleBeanInfo {

    private final BeanDescriptor beanDesc;
    private final PropertyDescriptor[] propDesc;

    protected ListRecognizingBeanInfo(Class<?> beanClass)
    throws IntrospectionException {
        beanDesc = new BeanDescriptor(beanClass);

        List<PropertyDescriptor> desc = new ArrayList<>();

        for (Method method : beanClass.getMethods()) {
            int modifiers = method.getModifiers();
            Class<?> type = method.getReturnType();

            if (Modifier.isPublic(modifiers) &&
                !Modifier.isStatic(modifiers) &&
                !type.equals(Void.TYPE) &&
                method.getParameterCount() == 0) {

                String name = method.getName();
                String remainder;
                if (name.startsWith("get")) {
                    remainder = name.substring(3);
                } else if (name.startsWith("is") &&
                           type.equals(Boolean.TYPE)) {
                    remainder = name.substring(2);
                } else {
                    continue;
                }

                if (remainder.isEmpty()) {
                    continue;
                }

                String propName = Introspector.decapitalize(remainder);

                Method writeMethod = null;
                Method possibleWriteMethod =
                    findMethod(beanClass, "set" + remainder, type);
                if (possibleWriteMethod != null &&
                    possibleWriteMethod.getReturnType().equals(Void.TYPE)) {

                    writeMethod = possibleWriteMethod;
                }

                Class<?> componentType = null;
                if (type.isArray()) {
                    componentType = type.getComponentType();
                } else {
                    Type genType = method.getGenericReturnType();
                    if (genType instanceof ParameterizedType) {
                        ParameterizedType p = (ParameterizedType) genType;
                        if (p.getRawType().equals(List.class)) {
                            Type[] argTypes = p.getActualTypeArguments();
                            if (argTypes[0] instanceof Class) {
                                componentType = (Class<?>) argTypes[0];
                            }
                        }
                    }
                }

                Method indexedReadMethod = null;
                Method indexedWriteMethod = null;

                if (componentType != null) {
                    Method possibleReadMethod =
                        findMethod(beanClass, name, Integer.TYPE);
                    Class<?> idxType = possibleReadMethod.getReturnType();
                    if (idxType.equals(componentType)) {
                        indexedReadMethod = possibleReadMethod;
                    }

                    if (writeMethod != null) {
                        possibleWriteMethod =
                            findMethod(beanClass, writeMethod.getName(),
                                Integer.TYPE, componentType);
                        if (possibleWriteMethod != null &&
                            possibleWriteMethod.getReturnType().equals(
                                Void.TYPE)) {

                            indexedWriteMethod = possibleWriteMethod;
                        }
                    }
                }

                if (indexedReadMethod != null) {
                    desc.add(new IndexedPropertyDescriptor(propName,
                        method, writeMethod,
                        indexedReadMethod, indexedWriteMethod));
                } else {
                    desc.add(new PropertyDescriptor(propName,
                        method, writeMethod));
                }
            }
        }

        propDesc = desc.toArray(new PropertyDescriptor[0]);
    }

    private static Method findMethod(Class<?> cls,
                                     String name,
                                     Class<?>... paramTypes) {
        try {
            Method method = cls.getMethod(name, paramTypes);
            int modifiers = method.getModifiers();
            if (Modifier.isPublic(modifiers) &&
                !Modifier.isStatic(modifiers)) {

                return method;
            }
        } catch (NoSuchMethodException e) {
        }

        return null;
    }

    @Override
    public BeanDescriptor getBeanDescriptor() {
        return beanDesc;
    }

    @Override
    public PropertyDescriptor[] getPropertyDescriptors() {
        return propDesc;
    }
}

关于java - JRE 1.8 是否仍然是 JavaBean 规范提示 Indexed PropertyDescriptor?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34726164/

相关文章:

java - Jackson 与泛型 JSON 无法构造 java.lang.Class 的实例

java - 使用 JAVA 等效的 OpenSSL 命令

在另一个 Service 中 Spring 注入(inject) Service

java - 未找到 bean NoSuchBeanDefinitionException

Java bean 测试框架

python - 如何获取python中最顶层(入口)脚本的名称?

java - JDK6 HTTP 服务器上带有 Spring 3 的 REST 服务

swift - 在运行时从 protocol.Type 引用动态实例化

php - 在 PHP 中使用变量 NAME 作为值

java - 使用gate处理文档时出现内存不足异常