首页 > 解决方案 > Java - 如何比较不同对象类型的列表

问题描述

我希望我能清楚地解释我的问题。

我正在开发一个 API 网关,以将 JSON 有效负载与外部 API (Okta) 进行比较,以了解为有效负载的每个对象执行哪个 HTTP 操作。

通常我会简单地在外部 API 上发出一个 GET 请求并比较两个 JSON,这会更容易。但是对于这个我使用 Okta 的 API SDK ( https://github.com/okta/okta-sdk-java ) 来发出这些请求,尤其是不必通过 POJO 定义我需要的所有对象我的项目。

所以我将我的 JSON 有效负载放入一个List由元素组成的元素Group(这是我想要使用的 SDK 中的一个元素)。然后,我使用 SDK 通过 API 获取 Okta 中的元素,并将其放入List也 of elementGroup中。这是代码:

List<Group> groupListBody = mapper.readValue(body, List.class);
List<Group> groupListOkta = okta.listGroups().stream().collect(Collectors.toList());

问题是 List 实际上由不同类型的 Objects 组成:

在此处输入图像描述

但是,如果我们取 和 的一个元素,groupListBody因为groupListOkta它们是由 object 定义的Group,我们可以清楚地看到它们除了类型之外是相同的。

在此处输入图像描述

在此处输入图像描述

所以我的问题是,我能做些什么来改变它们的类型或其他东西来正确比较这两个列表的元素?

更新 :

我注意到杰克逊创建了一个列表,LinkedHashMap因为它没有足够的信息将我的有效负载反序列化为Group对象列表。

如果我将列表中的一个元素用

Group test = (Group) groupListBody.get(0);

ERROR::class java.util.LinkedHashMap cannot be cast to class com.okta.sdk.resource.group.Group (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.okta.sdk.resource.group.Group is in unnamed module of loader 'app')

我认为它来自Group对象的 SDK 模型,但我不知道如何在不重新创建 POJO 模型的情况下正确反序列化它。

这是模型类:

public interface Group extends ExtensibleResource, Deletable {

    Map<String, Object> getEmbedded();

    Map<String, Object> getLinks();

    Date getCreated();

    String getId();

    Date getLastMembershipUpdated();

    Date getLastUpdated();

    List<String> getObjectClass();

    GroupProfile getProfile();

    Group setProfile(GroupProfile profile);

    GroupType getType();

    Role assignRole(AssignRoleRequest assignRoleRequest, String disableNotifications);

    Role assignRole(AssignRoleRequest assignRoleRequest);

    UserList listUsers();

    Group update();

    void removeUser(String userId);

    ApplicationList listApplications();

    void delete();
}

标签: javalistapisdkokta

解决方案


编辑:我已经阅读了您帖子的更新。如果您确实必须比较这两种对象类型而不将它们复制到新列表中,您可能会发现这种方法很有用:

在 Java 中,我们有 Collector 接口,它是一个通用接口,定义如下:

    Public interface collector <T,A,R>{
    Supplier<A> supplier();
    BiConsumer<A,T> accumulator()
    BinaryOperator<A> combiner()
    Function<A,R> finisher();
    Set<characteristics> characteristics();
    }
    

现在,我们可以通过定义一个实现我上面提供的所有方法的新类来实现这个接口的自定义收集器。但首先,这一切到底意味着什么?

  1. 元素<T,A,R>: -T 是流提供的元素的对象类型 -A 累加器在收集元素时将调用的对象类型 -R 收集方法返回的对象类型

  2. 方法: -Supplier() 提供保存累积操作结果的容器。Supplier 是一个工厂函数,它返回对方法的引用。-accumulator() 消耗元素以累积它们 -combiner() 统一累积结果 -finisher() 将保存累积结果的容器转换为所需类型 -characteristics() 定义流以并行或顺序计算运行时的行为(例如:并发或无序)。

如果这种方法对您不起作用,我们可以通过一些有用的方法来更好地控制输入数据的输出。

    List<Group> groupListOkta = 
    okta.listGroups().stream().collectAndThen(Collector<T,A,R> 
    downstream, Function<R,RR> modifier()) //Passes the collector 
    //to a finisher function, in which you can return the desired type.

如果您想阅读有关该主题的更多信息,这里有一些有用的链接:

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toCollection-java.util.function.Supplier- https://docs.oracle.com/javase/ 8/docs/api/java/util/stream/Collectors.html https://www.technetexperts.com/web/how-to-use-custom-collectors-in-java/ https://docs.oracle.com /javase/8/docs/api/java/util/stream/Collectors.html#collectingAndThen-java.util.stream.Collector-java.util.function.Function-

再会,

虽然有点乏味,但您可以编写一个循环遍历对象的所有元素的函数,然后创建一个新的布尔数组列表。此列表将为您提供其索引处的所有匹配项。

    public static List<Boolean> checkMatches( List<Group> l1, List<Group> l2 ) {

    //Optionally, you can check here which list is shortest and store 
    //this somewhere, enabling you to preset matches.length

    List<Boolean> matches = new ArrayList<>();
    int count = 0;
    for ( Object o1 : l2 ) {
    count++
    for ( Object o2 : l1 ) {
    if (o1.equals(o2){
    matches.add(true)
    };
    };
    if (matches.length < count){
    matches.add(false)
    };
    };
    return matches;
    };

这个想法是,如果在其他对象中找到匹配项,则添加 true,然后通过比较长度检查是否添加了 true,如果没有添加 true,则添加 false。


推荐阅读