Сравнить поля двух не связанных между собой объектов - PullRequest
0 голосов
/ 12 октября 2010

У меня есть два объекта разных классов, которые имеют несколько полей с одинаковыми именами и типами. Эти два объекта не связаны друг с другом. У меня нет возможности создать интерфейс или родительский класс.

Теперь я хочу сравнить эти общие поля, и насколько я знаю, это должно быть возможно с помощью отражения.

Вот шаги, которые я написал для такого метода сравнения:

Field[] inputFields = input.getClass().getDeclaredFields();
for (Field field : inputFields ) {
    log.info(field.getName() + " : " + field.getType());
}

Будет объект с именем database, с полями которого сравниваются inputFields.

К сожалению, я не знаю, как получить значение моих полей. У вас есть намеки на меня?


Хорошо, с field.get(input) Теперь я получил значение, но, возможно, я ошибся, и это не то, что мне нужно. На самом деле я хочу сравнить это поле с другим, поэтому мне нужно вызвать метод equals для этого поля. Но сначала я должен привести его в соответствующий класс. Так есть ли что-то вроде ((field.getClass()) field).equals(...), которое будет работать?

Ответы [ 3 ]

2 голосов
/ 12 октября 2010

Я думаю, что вы ищете Field.get():

for (Field field : inputFields ) {
    log.info(field.getName() + " : " 
             + field.getType() + " = " 
             + field.get(input);
}
0 голосов
/ 12 октября 2010

Вот решение этой проблемы, служебный класс с именем FieldHelper, имеющий метод

Map<String, Object[]> properties =
    FieldHelper.getCommonProperties(Object a, Object b)

Возвращенная карта имеет имя поля в качестве ключа и массив двух значений поля в качестве значения:

public final class FieldHelper{

    private FieldHelper(){}

    private static final Map<Class<?>, Map<String, PropertyDescriptor>> cache =
        new HashMap<Class<?>, Map<String, PropertyDescriptor>>();

    /**
     * Return a Map of field names to {@link PropertyDescriptor} objects for a
     * given bean.
     */
    public static Map<String, PropertyDescriptor> getBeanProperties(final Object o){

        try{
            final Class<?> clazz = o.getClass();
            Map<String, PropertyDescriptor> descriptors;
            if(cache.containsKey(clazz)){
                descriptors = cache.get(clazz);
            } else{
                final BeanInfo beanInfo =
                    Introspector.getBeanInfo(clazz, Object.class);
                descriptors = new TreeMap<String, PropertyDescriptor>();
                for(final PropertyDescriptor pd : beanInfo.getPropertyDescriptors()){
                    descriptors.put(pd.getName(), pd);
                }
                cache.put(clazz,
                    new TreeMap<String, PropertyDescriptor>(descriptors));
            }
            final Map<String, PropertyDescriptor> beanProperties = descriptors;
            return beanProperties;

        } catch(final IntrospectionException e){
            throw new IllegalStateException("Can't get bean metadata", e);
        }
    }

    /**
     * Return a Map of all field names and their respective values that two
     * objects have in common. Warning: the field values can be of different
     * types.
     */
    public static Map<String, Object[]> getCommonProperties(final Object a,
        final Object b){
        final Map<String, PropertyDescriptor> aProps = getBeanProperties(a);
        final Map<String, PropertyDescriptor> bProps = getBeanProperties(b);
        final Set<String> aKeys = aProps.keySet();
        final Set<String> bKeys = bProps.keySet();
        aKeys.retainAll(bKeys);
        bKeys.retainAll(aKeys);
        final Map<String, Object[]> map = new TreeMap<String, Object[]>();

        for(final String propertyName : aKeys){
            final Object aVal = getPropertyValue(a, aProps.get(propertyName));
            final Object bVal = getPropertyValue(b, bProps.get(propertyName));
            map.put(propertyName, new Object[] { aVal, bVal });
        }
        return map;
    }

    /**
     * Return the value of a bean property, given the bean and the {@link PropertyDescriptor}.
     */
    private static Object getPropertyValue(final Object a,
        final PropertyDescriptor propertyDescriptor){
        try{
            return propertyDescriptor.getReadMethod().invoke(a);
        } catch(final IllegalArgumentException e){
            throw new IllegalStateException("Bad method arguments", e);
        } catch(final IllegalAccessException e){
            throw new IllegalStateException("Can't access method", e);
        } catch(final InvocationTargetException e){
            throw new IllegalStateException("Invocation error", e);
        }
    }

Код теста:

public static void main(final String[] args){
    class Foo{
        private String abc = "abc";
        private String defy = "defy";
        private String ghi = "ghi";
        private String jkl = "jkl";
        // stripped getters and setters
        // they must be there for this to work
    }
    class Bar{
        private Boolean abc = true;
        private Integer def = 3;
        private String ghix = "ghix3";
        private Date jkl = new Date();
        // stripped getters and setters
        // they must be there for this to work
    }
    final Map<String, Object[]> properties =
        getCommonProperties(new Foo(), new Bar());
    for(final Entry<String, Object[]> entry : properties.entrySet()){
        System.out.println("Field: " + entry.getKey() + ", value a: "
            + entry.getValue()[0] + ", value b: " + entry.getValue()[1]);
    }
}

Выход:

Поле: abc, значениеa: abc, значение b: true
Поле: jkl, значение a: jkl, значение b: вт 12 октября 14:03:31 CEST 2010

Примечание: этот код на самом деле неПрочитайте поля, это следует за соглашением Java-бина и использует вместо этого получатели.Было бы легко переписать его для использования полей, но я бы посоветовал против этого.

0 голосов
/ 12 октября 2010

Отметьте отдельную главу руководства Sun по Java. Эта страница отвечает на ваш конкретный вопрос с примером.

...