2016-01-11 9 views
4

Этот вопрос кажется неудобным, но мы сталкиваемся с странным поведением при извлечении PropertyDescriptors javabean. Вот результаты выполнения 1,6, 1,7 и 1,8 простой части кода, составленной с соблюдением 1.6.Является ли JRE 1.8 еще спецификациями JavaBean совместимыми с IndexedPropertyDescriptor?

Java 1.6 выполнение:

< [email protected] - Не важно [email protected] < - Да у меня есть индексированный свойство

Java 1.7 Выполнение:

java.beans.PropertyDescriptor [name = class; propertyType = class java.lang.Class; readMethod = public final native java.lang.Class java.lang.Object.getClass()] < - не важно java.beans.IndexedPropertyDescriptor [name = values; indexedPropertyType = класс java.lang.String; indexedReadMethod = java.lang.String JavaBean.getValues ​​общественного (интермедиат)] < - Да у меня есть индексированное свойство

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 [name = values; propertyType = interface java.util.List; readMethod = public java.util.List JavaBean.getValues ​​()] < - Ой! Это уже не индексированное свойство!

Почему это изменилось?

В javabean specs говорится о доступе к объекту с индексом. Не считается обязательным использовать массив в качестве контейнера с индексированным свойством. Я ошибаюсь?

Я прочитал спецификации и главу 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); 
     } 
    } 
} 

ответ

2

От JavaBeans 1,01 спецификации, раздел 7.2 «Индексированные свойства»:

Компонент также может выставлять индексированное свойство как одно значение массива.

В разделе 8.3 описываются шаблоны проектирования, которые introspection признает в отсутствие явного BeanInfo. В разделе 8.3.3 говорится, что только свойства массива будут инициировать автоматическое распознавание индексированных свойств.

Вы технически верны; не обязательно использовать массив. Но если вы этого не сделаете, спецификация заявляет, что вы должны предоставить свою собственную BeanInfo, чтобы выставить свойство как индексированное свойство.

Итак, ответ на ваш вопрос: Да, Java 1.8 - это спецификации JavaBean.

Я не уверен, почему свойства списка когда-либо поддерживались. Возможно, будущая спецификация JavaBeans будет поддерживать их, которые с тех пор были сняты.

Что касается вашего последнего вопроса: я думаю, вам нужно будет создать класс BeanInfo для каждого класса со свойствами List. Я ожидаю, что вы сможете создать общий суперкласс, чтобы сделать его проще, например:

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; 
    } 
} 
+0

Ну ... Я ожидал такого ответа. Я до сих пор не понимаю, почему поведение изменилось таким образом, к более ограничительной реализации. Отличный ответ. Благодарю. Поскольку мы используем commons-beanutils, я предпочитаю расширять возможности этого API, используя BeanIntrospector, который может обнаружить IndexedProperty в моем собственном определении во время изучения компонента. –