Динамическое сравнение объектов двух разных классов на основе исключительно общих свойств - PullRequest
1 голос
/ 06 марта 2019

Я пишу некоторые полностью динамические методы, в которых мне нужно сравнить два объекта разных классов.

Вот пример объектов:

public class Object1 {

    private String lastname;
    private String firstname;
    private int age;
    private int gender;

    //All getters and setters
}

public class Object2 {

    private String lastname;
    private String address;
    private String job;

    //All getters and setters

}

Как вы можете видеть здесь, единственное общее свойство - это фамилия, поэтому я хочу, чтобы мое сравнение применялось только к фамилии

Дополнительно:

  • В моем реальном коде я использую много разных классов, я не могу заставить их реализовывать общие интерфейсы, на самом деле, я вообще не могу их изменять
  • Я не знаю, какие свойства могут быть общими, поэтому я не могу жестко закодировать свои тесты
  • Я использую Java 8

Итак, я ищу какой-то класс, похожий на BeanUtils, в котором есть метод copyProperties для общих свойств, но здесь вместо копирования я бы хотел сравнить.

Я думаю, что такой класс полезности может существовать, но я не могу его найти.

Так что, если у вас есть идея, я буду рад ее прочитать:)

Спасибо!

[Изменить 1] Дополнительные сведения о том, почему я хочу это сделать:

Я пишу общую систему для генерации конечных точек для REST Api на основе JAX-RS (Джерси). Я использую интерфейсы с обобщенными типами, как этот «простой» пример:

public interface sampleEndpoint<BEANPARAM,BODYREQUEST,RESPONSE>  {

    @PUT
    @Path("/{id}")
    default RESPONSE update(@Valid @BeanParam BEANPARAM bp, @Valid BODYREQUEST body) {
        //Check if id in path is the same as id in the body

        ....
    }


}

(С Джерси мы не можем использовать BeanParam для извлечения в том же Bean PathParam, QueryParam и RequestBody ... вот почему мне нужно использовать и BeanParam, и другой bean-компонент для тела)

Мои варианты использования могут быть более сложными, но это простая иллюстрация.

Ответы [ 2 ]

0 голосов
/ 08 марта 2019

Я закончил создавать свой собственный класс, чтобы достичь того, чего я хочу.

Я решил использовать Джексон (fastxml), чтобы преобразовать мой объект в JsonNode, а затем рекурсивно сравнить JsonNodes.

Вот код (мне нужно сделать несколько тестов, чтобы проверить его глубже, но он работает для моих случаев использования):

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Iterator;

public class ObjectComparator {


    /**
     * For each attribute of «expected» Object, verify if this attribute exists in «actual» and if it exists, verify if the value is the same as the «expected» one
     *
     * @param expected : the reference JsonNode
     * @param actual : the Object in which we want to verify the attributes
     * @return true if all commons attributes between «expected» and «actual» have same values, otherwise returns false
     */
    public static boolean CommonsAttributesComparator(Object expected, Object actual) {

        ObjectMapper mapper = new ObjectMapper();
        JsonNode expectedNode = mapper.convertValue(expected, JsonNode.class);
        JsonNode actualNode = mapper.convertValue(actual, JsonNode.class);

        return(JsonNodeComparator(expectedNode, actualNode));
    }


    /**
     * For each attribute of «expected» JsonNode, verify if this attribute exists in «actual» and if it exists, verify if the value is the same as the «expected» one
     *
     * @param expectedNode : the reference JsonNode
     * @param actualNode : the JsonNode in which we want to verify the attributes
     * @return true if all commons attributes between «expected» and «actual» have same values, otherwise returns false
     */
    public static boolean JsonNodeComparator(JsonNode expectedNode, JsonNode actualNode) {

        Iterator<String> expectedKeys =  expectedNode.fieldNames();
        if(!expectedKeys.hasNext()) {
            return expectedNode.equals(actualNode);
        }
        while (expectedKeys.hasNext()) {
            String currentKey = expectedKeys.next();
            if (
                    !expectedNode.get(currentKey).isNull()
                            && actualNode.has(currentKey)
                            && !actualNode.get(currentKey).isNull()) {

                if (expectedNode.get(currentKey).isArray()) {
                    if (actualNode.get(currentKey).isArray()
                    && actualNode.get(currentKey).size() == expectedNode.get(currentKey).size()) {

                        boolean subNodeComparisonSucceeded = false;
                        for (final JsonNode expectedSubNode : expectedNode.get(currentKey)) {
                            for (final JsonNode actualSubNode : actualNode.get(currentKey)) {
                                subNodeComparisonSucceeded = JsonNodeComparator(expectedSubNode, actualSubNode);
                                if(subNodeComparisonSucceeded) {
                                    break;
                                }
                            }
                            if(!subNodeComparisonSucceeded) {
                                return false;
                            }
                        }
                    } else if(expectedNode.get(currentKey).size() > 0) {
                        return false;
                    }
                } else if(!expectedNode.get(currentKey).equals(actualNode.get(currentKey))) {
                    return false;
                }
            }
        }
        return true;
    }
}
0 голосов
/ 06 марта 2019

Из того, что я понял, кажется, что Reflection API - это именно то, что вы ищете.Вы можете получить список всех полей в каждом классе и затем сравнить значения двух полей, только если они имеют одинаковые имена.

Основное преимущество этого подхода состоит в том, что он может быть обобщендля любых двух классов.Однако на Reflection часто возмущаются, потому что это нарушает инкапсуляцию, и я бы порекомендовал вам найти лучшее решение, специфичное для вашей проблемы, прежде чем соглашаться на эту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...