如何将任何对象序列化为URI?

时间:2022-06-13 18:06:49

My basic question: is there anything built that already does this automatically (doesn't have to be part of a popular library/package)? The main things I'm working with are Spring (MVC) and Jackson2.

我的基本问题是:是否有任何东西已经自动完成了(不一定是流行的库/包的一部分)?我主要使用的是Spring (MVC)和Jackson2。

I understand there are a few manual ways to do this:

我知道有一些手动的方法可以做到这一点:

  1. Create a method in each class that serializes its specific properties into property=value& form (kind of stinks because it's a bunch of logic duplication, I feel).
  2. 在每个类中创建一个方法,将它的特定属性序列化为property= value&form(我觉得有点臭,因为它有很多逻辑重复)。
  3. Create a function that accepts an object, and uses reflection to dynamically read all the properties (I guess the getters), and build the string by getting each. I'm assuming this is how Jackson works for serialization/deserialization in general, but I really don't know.
  4. 创建一个接受对象的函数,并使用反射动态读取所有属性(我猜是getter),并通过获取每个属性来构建字符串。我假设这就是Jackson对于序列化/反序列化的工作原理,但我真的不知道。
  5. Use some feature of Jackson to customly serialize the object. I've researched custom serializers, but it seems they are specific to a class (so I'd have to create one for each Class I'm trying to serialize), while I was hoping for a generic way. I'm just having trouble understanding how to apply one universally to objects. A few of the links:
  6. 使用Jackson的一些特性来定制序列化对象。我已经研究了自定义序列化器,但它们似乎是特定于类的(因此我必须为我要序列化的每个类创建一个),而我希望有一种通用的方式。我只是搞不懂如何把一个普遍地应用到物体上。其中有几个链接:http://techtraits.com/programming/2011/11/20/using-customserializers-with-jackson/ http://wiki.fasterxml.com/jacksonhowtocustomserializer。
  7. Use ObjectMapper.convertValue(object, HashMap.class);, iterate over the HashMap's key/value pairs, and build the string (which is what I'm using now, but I feel the conversions are excessive?).
  8. 使用objectmap。convertValue(object, HashMap.class);,遍历HashMap的键/值对,并构建字符串(这就是我现在使用的,但我觉得转换是过度的?)
  9. I'm guessing there's others I'm not thinking of.
  10. 我猜还有其他我没有想到的。

The main post I've looked into is Java: Getting the properties of a class to construct a string representation

我研究过的主要文章是Java:获取类的属性来构造字符串表示

My point is that I have several classes that I want to be able to serialize without having to specify something specific for each. That's why I'm thinking a function using reflection (#2 above) is the only way to handle this (if I have to do it manually).

我的观点是,我有几个类,我希望能够序列化,而不必为每个类指定特定的内容。这就是为什么我认为使用反射(上面的#2)的函数是处理这个问题的唯一方法(如果我必须手动处理的话)。

If it helps, an example of what I mean is with, say, these two classes:

如果有帮助的话,我的意思的一个例子就是,这两个类:

public class C1 {
    private String C1prop1;
    private String C1prop2;
    private String C1prop3;

    // Getters and setters for the 3 properties
}

public class C2 {
    private String C2prop1;
    private String C2prop2;
    private String C2prop3;

    // Getters and setters for the 3 properties
}

(no, the properties names and conventions are not what my actual app is using, it's just an example)

(不,属性名和约定不是我实际使用的应用程序,它只是一个例子)

The results of serializing would be C1prop1=value&C1prop2=value&C1prop3=value and C2prop1=value&C2prop2=value&C2prop3=value, but there's only one place that defines how the serialization happens (already defined somewhere, or created manually by me).

序列化的结果是C1prop1=value&C1prop2=value&C1prop3=value, C2prop1=value&C2prop2=value&C2prop3=value,但是只有一个地方可以定义序列化是如何发生的(已经在某处定义了,或者是我手工创建的)。

So my idea is that I will have to end up using a form of the following (taken from the post I linked above):

因此,我的想法是,我将不得不采用以下形式(摘自我在上面链接的帖子):

public String toString() {
    StringBuilder sb = new StringBuilder();
    try {
        Class c = Class.forName(this.getClass().getName());
        Method m[] = c.getDeclaredMethods();
        Object oo;
        for (int i = 0; i < m.length; i++)
        if (m[i].getName().startsWith("get")) {
            oo = m[i].invoke(this, null);
            sb.append(m[i].getName().substring(3) + ":"
                      + String.valueOf(oo) + "\n");
        }
    } catch (Throwable e) {
        System.err.println(e);
    }
    return sb.toString();
}

And modify it to accept an object, and change the format of the items appended to the StringBuilder. That works for me, I don't need help modifying this now.

并修改它以接受一个对象,并更改附加到StringBuilder的项的格式。这对我来说是可行的,我现在不需要修改这个。

So again, my main question is if there's something that already handles this (potentially simple) serialization instead of me having to (quickly) modify the function above, even if I have to specify how to deal with each property and value and how to combine each?

因此,我的主要问题是,如果有什么东西已经处理了(可能很简单)序列化,而不是必须(快速)修改上面的函数,即使我必须指定如何处理每个属性和值以及如何组合它们?

If it helps, the background of this is that I'm using a RestTemplate (Spring) to make a GET request to a different server, and I want to pass a specific object's properties/values in the URL. I understand I can use something like:

如果有帮助的话,它的背景是我正在使用一个RestTemplate (Spring)向另一个服务器发出一个GET请求,并且我想在URL中传递一个特定对象的属性/值。我知道我可以使用以下内容:

restTemplate.getForObject("URL?C1prop1={C1Prop1}&...", String.class, C1Object);

I believe the properties will be automatically mapped. But like I said, I don't want to have to make a different URL template and method for each object type. I'm hoping to have something like the following:

我相信属性会自动映射。但是就像我说的,我不想为每个对象类型创建不同的URL模板和方法。我希望有如下的东西:

public String getRequest(String url, Object obj) {
    String serializedUri = SERIALIZE_URI(obj);
    String response = restTemplate.getForObject("URL?" + serializedUri, String.class);
    return response;
}

where SERIALIZE_URI is where I'd handle it. And I could call it like getRequest("whatever", C1Object); and getRequest("whateverElse", C2Object);.

SERIALIZE_URI就是我要处理的地方。我可以把它叫做getRequest(“whatever”,C1Object);和getRequest(“whateverElse C2Object);。

2 个解决方案

#1


15  

I think, solution number 4 is OK. It is simple to understand and clear.

我认为,解4是可以的。这很容易理解,也很清楚。

I propose similar solution in which we can use @JsonAnySetter annotation. Please, see below example:

我提出了类似的解决方案,我们可以使用@JsonAnySetter注释。请参见下面的例子:

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonProgram {

    public static void main(String[] args) throws Exception {
        C1 c1 = new C1();
        c1.setProp1("a");
        c1.setProp3("c");

        User user = new User();
        user.setName("Tom");
        user.setSurname("Irg");

        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.convertValue(c1, UriFormat.class));
        System.out.println(mapper.convertValue(user, UriFormat.class));
    }
}

class UriFormat {

    private StringBuilder builder = new StringBuilder();

    @JsonAnySetter
    public void addToUri(String name, Object property) {
        if (builder.length() > 0) {
            builder.append("&");
        }
        builder.append(name).append("=").append(property);
    }

    @Override
    public String toString() {
        return builder.toString();
    }
}

Above program prints:

以上程序打印:

prop1=a&prop2=null&prop3=c
name=Tom&surname=Irg

And your getRequest method could look like this:

你的getRequest命令可以是这样的:

public String getRequest(String url, Object obj) {
    String serializedUri = mapper.convertValue(obj, UriFormat.class).toString();
    String response = restTemplate.getForObject(url + "?" + serializedUri, String.class);
    return response;
}

#2


2  

Lets we have c1.

让我们有c1。

c1.setC1prop1("C1prop1");
c1.setC1prop2("C1prop2");
c1.setC1prop3("C1prop3");

Converts c1 into URI

c1转换成URI

    UriComponentsBuilder.fromHttpUrl("http://test.com")
            .queryParams(new ObjectMapper().convertValue(c1, LinkedMultiValueMap.class))
            .build()
            .toUri());

After we will have

之后我们会有

    http://test.com?c1prop1=C1prop1&c1prop2=C1prop2&c1prop3=C1prop3

#1


15  

I think, solution number 4 is OK. It is simple to understand and clear.

我认为,解4是可以的。这很容易理解,也很清楚。

I propose similar solution in which we can use @JsonAnySetter annotation. Please, see below example:

我提出了类似的解决方案,我们可以使用@JsonAnySetter注释。请参见下面的例子:

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonProgram {

    public static void main(String[] args) throws Exception {
        C1 c1 = new C1();
        c1.setProp1("a");
        c1.setProp3("c");

        User user = new User();
        user.setName("Tom");
        user.setSurname("Irg");

        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.convertValue(c1, UriFormat.class));
        System.out.println(mapper.convertValue(user, UriFormat.class));
    }
}

class UriFormat {

    private StringBuilder builder = new StringBuilder();

    @JsonAnySetter
    public void addToUri(String name, Object property) {
        if (builder.length() > 0) {
            builder.append("&");
        }
        builder.append(name).append("=").append(property);
    }

    @Override
    public String toString() {
        return builder.toString();
    }
}

Above program prints:

以上程序打印:

prop1=a&prop2=null&prop3=c
name=Tom&surname=Irg

And your getRequest method could look like this:

你的getRequest命令可以是这样的:

public String getRequest(String url, Object obj) {
    String serializedUri = mapper.convertValue(obj, UriFormat.class).toString();
    String response = restTemplate.getForObject(url + "?" + serializedUri, String.class);
    return response;
}

#2


2  

Lets we have c1.

让我们有c1。

c1.setC1prop1("C1prop1");
c1.setC1prop2("C1prop2");
c1.setC1prop3("C1prop3");

Converts c1 into URI

c1转换成URI

    UriComponentsBuilder.fromHttpUrl("http://test.com")
            .queryParams(new ObjectMapper().convertValue(c1, LinkedMultiValueMap.class))
            .build()
            .toUri());

After we will have

之后我们会有

    http://test.com?c1prop1=C1prop1&c1prop2=C1prop2&c1prop3=C1prop3