简体   繁体   English

Java - 如何比较不同对象类型的列表

[英]Java - How to compare list of different Object types

I hope I'm going to be clear enough to explain my problem.我希望我能足够清楚地解释我的问题。

I'm developing an API gateway to compare a JSON payload to an external API (Okta) to know which HTTP action to do for every object of the payload.我正在开发一个 API 网关来将 JSON 有效负载与外部 API (Okta) 进行比较,以了解对有效负载的每个对象执行哪个 HTTP 操作。

Usually I would simply make a GET request on the external API and compare both JSON, which would be way easier.通常我会简单地在外部 API 上发出一个 GET 请求并比较两个 JSON,这会更容易。 But for this one I'm using the Okta's API SDK ( https://github.com/okta/okta-sdk-java ) to make those requests and especially to not have to define all objects by POJOs that I'll need in my project.但是对于这个,我使用 Okta 的 API SDK ( https://github.com/okta/okta-sdk-java ) 来发出这些请求,尤其是不必通过 POJO 定义我需要的所有对象我的项目。

So I'm taking my JSON payload and put it inside a List composed of the element Group (which is an element from the SDK that I want to use).所以我将我的 JSON 负载放入一个由元素Group (这是我想要使用的 SDK 中的元素)组成的List I'm then using the SDK to get the elements inside Okta through the API and put it inside a List also of element Group .然后我使用 SDK 通过 API 获取 Okta 中的元素,并将其放入元素GroupList中。 Here is the code :这是代码:

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

The thing is that the List are in fact composed of differents types of Objects :问题是 List 实际上由不同类型的 Objects 组成:

  • JSON Payload list is a List of LinkedHashMap Objects JSON Payload 列表是一个LinkedHashMap对象List
  • Okta list is a List of DefaultGroup Objects Okta 列表是DefaultGroup对象的List

在此处输入图片说明

But if we take an element of groupListBody and groupListOkta as they were defined by the object Group , we can cleary see that they are identical except for their type.但是,如果我们采用对象Group定义的groupListBodygroupListOkta元素,我们可以清楚地看到它们除了类型之外是相同的。

在此处输入图片说明

在此处输入图片说明

So my question is, what can I do to change either their type or something else to properly compare the elements of those two lists?所以我的问题是,我能做些什么来改变它们的类型或其他东西来正确比较这两个列表的元素?

UPDATE :更新 :

I've noticed that jackson create a list of LinkedHashMap because it does not have enough information to deserialize my payload into a list of Group objects.我注意到 jackson 创建了一个LinkedHashMap列表,因为它没有足够的信息将我的有效负载反序列化为一个Group对象列表。

Here is what happend if I cast a element of the list with如果我将列表的一个元素与

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')

I think it's coming from the SDK model of the Group object but I don't know what to do to properly deserialze it without recreating a POJO model.我认为它来自Group对象的 SDK 模型,但我不知道如何正确反序列化它而不重新创建 POJO 模型。

Here is the model class :这是模型类:

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();
}

EDIT: I've read the update on your post.编辑:我已经阅读了您帖子中的更新。 If you really must compare these two objecttypes without copying them into a new list, you might find this approach useful:如果您真的必须比较这两种对象类型而不将它们复制到新列表中,您可能会发现这种方法很有用:

In Java, we have the Collector interface, which is a generic interface, that is defined as following:在 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();
    }
    

Now, we can make a custom collector implementing this interface, by defining a new class that implements all the methods that I provided above.现在,我们可以通过定义一个实现我上面提供的所有方法的新类来创建一个实现此接口的自定义收集器。 But first, what does all of this mean anyway?但首先,这一切意味着什么?

  1. The elements <T,A,R>: -T is objecttype of the elements provided by the stream -A Type of object that the accumulator will call when collecting elements -R Type of object returned by the collect method元素<T,A,R>: -T 是流提供的元素的对象类型 -A 收集元素时累加器将调用的对象类型 -R collect 方法返回的对象类型

  2. The methods: -Supplier() provides the container that holds the results of the accumulation operation.方法: -Supplier() 提供保存累积操作结果的容器。 Supplier is a factory function, that returns a reference to a method.供应商是一个工厂函数,它返回对方法的引用。 -accumulator() consumes elements for accumulating them -combiner() unifies the accumulated results -finisher() transforms the container holding the accumulated result into desired type -characteristics() defines behaviour when stream is ran in parallel or sequential computing (for example: Concurrent or Unordered). -accumulator() 消耗元素来累积它们 -combiner() 统一累积的结果 -finisher() 将保存累积结果的容器转换为所需的类型 -characteristics() 定义在并行或顺序计算中运行流时的行为(例如:并发或无序)。

If this approach doesn't work for you, we can gain more control over the output of our input data with some helpful methods.如果这种方法对您不起作用,我们可以通过一些有用的方法更好地控制输入数据的输出。

    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.

If you would like to read more about the topic, here are some helpful links:如果您想阅读有关该主题的更多信息,这里有一些有用的链接:

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- 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-

Good day,再会,

although it is a bit tedious, you can write a function that loops over all the elements of your objects, then creates a new arraylist of booleans.虽然有点乏味,但您可以编写一个函数来循环遍历对象的所有元素,然后创建一个新的布尔值数组列表。 This list will give you all the matches at their indexes.此列表将为您提供其索引处的所有匹配项。

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

I coded this a bit hastily.我有点仓促地编码了这个。 The idea is that you add true if you find a match in your other object, then check if you added true by comparing length, and when u have not added true, u add false.这个想法是,如果您在其他对象中找到匹配项,则添加 true,然后通过比较长度检查您是否添加了 true,如果您没有添加 true,则添加 false。 You can make this more pretty and more efficient I trust.我相信你可以让它更漂亮、更高效。 I hope that the solution works for you!我希望该解决方案对您有用!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM