Chuyển đổi Bản đồ <Chuỗi, Chuỗi> thành POJO


185

Tôi đã nhìn vào Jackson, nhưng dường như tôi sẽ phải chuyển đổi Bản đồ thành JSON, và sau đó JSON kết quả thành POJO.

Có cách nào để chuyển đổi Bản đồ trực tiếp thành POJO không?

Câu trả lời:


355

Chà, bạn cũng có thể đạt được điều đó với Jackson. (và có vẻ thoải mái hơn vì bạn đang cân nhắc sử dụng jackson).

Sử dụng ObjectMapper's convertValuephương pháp:

final ObjectMapper mapper = new ObjectMapper(); // jackson's objectmapper
final MyPojo pojo = mapper.convertValue(map, MyPojo.class);

Không cần phải chuyển đổi thành chuỗi JSON hoặc cái gì khác; chuyển đổi trực tiếp làm nhanh hơn nhiều.


8
Bạn cần bao gồm thư viện này để sử dụng ObjectMappercompile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
Shajeel Afzal

5
Sử dụng convertValue là câu trả lời đúng, nhưng đừng tạo một đối tượng ObjectMapper mỗi lần. Thật tốn kém để tạo và an toàn luồng, vì vậy hãy tạo một cái và lưu trữ nó ở đâu đó.
glade

1
Bạn có biết cách làm ngược lại - hoặc cách chuyển đổi một đối tượng thành Bản đồ <Chuỗi, Đối tượng> không?
anon58192932

2
@RaduSimionescu bạn đã tìm ra cách chuyển đổi sâu các đối tượng với các bản đồ / danh sách lồng nhau thành một Map<String, Object>thể hiện chưa?
anon58192932

@ anon58192932 nó hoạt động nếu bạn làm theo câu trả lời này. Tôi chỉ đang xử lý một số đối tượng kỳ lạ đang lập mô hình danh sách dưới dạng bản đồ và khi việc xê-ri hóa nhận được kết quả bất ngờ. nhưng đó là một vấn đề khác, không liên quan gì đến jackson
Radu Simionescu

60

Một giải pháp với Gson :

Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(map);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);

1
Điều gì sẽ là ngược lại
Mitchs

2
@Prabs - Ngược lại sẽ là gson.toJson ()
AlikElzin-kilaka

Không cần phải chuyển đổi bản đồ sang json. map.toString () là đủ. Gson gson = Gson mới (); MyPojo pojo = gson.fromJson (map.toString (), MyPojo. Class);
Esakkiappan .E

1
@ Esakkiappan.E, tại sao bạn nghĩ map.toString()sẽ cung cấp đúng chuỗi? Việc thực hiện toString()không đảm bảo một định dạng cụ thể.
AlikElzin-kilaka

4

Có, chắc chắn có thể tránh được việc chuyển đổi trung gian sang JSON. Sử dụng một công cụ sao chép sâu như Dozer, bạn có thể chuyển đổi bản đồ trực tiếp thành POJO. Đây là một ví dụ đơn giản:

Ví dụ POJO:

public class MyPojo implements Serializable {
    private static final long serialVersionUID = 1L;

    private String id;
    private String name;
    private Integer age;
    private Double savings;

    public MyPojo() {
        super();
    }

    // Getters/setters

    @Override
    public String toString() {
        return String.format(
                "MyPojo[id = %s, name = %s, age = %s, savings = %s]", getId(),
                getName(), getAge(), getSavings());
    }
}

Mã chuyển đổi mẫu:

public class CopyTest {
    @Test
    public void testCopyMapToPOJO() throws Exception {
        final Map<String, String> map = new HashMap<String, String>(4);
        map.put("id", "5");
        map.put("name", "Bob");
        map.put("age", "23");
        map.put("savings", "2500.39");
        map.put("extra", "foo");

        final DozerBeanMapper mapper = new DozerBeanMapper();
        final MyPojo pojo = mapper.map(map, MyPojo.class);
        System.out.println(pojo);
    }
}

Đầu ra:

MyPojo [id = 5, name = Bob, tuổi = 23, tiết kiệm = 2500,39]

Lưu ý: Nếu bạn thay đổi bản đồ nguồn của mình thành a Map<String, Object>thì bạn có thể sao chép các thuộc tính lồng nhau sâu tùy ý (với Map<String, String>bạn chỉ nhận được một cấp).


1
Làm thế nào bạn có thể thực hiện một "bản sao sâu" từ Bản đồ sang POJO? Ví dụ: bạn có một User. Class đóng gói một Địa chỉ. Lớp và bản đồ có một khóa như "address.city", "address.zip" và những thứ này cần ánh xạ tới User.Address.City và User.Address.Zip ? Dường như nó không tự động diễn giải dấu chấm trong khóa Bản đồ dưới dạng cấp phụ cho biểu đồ đối tượng.
szxnyc

4

nếu bạn có loại chung trong lớp, bạn nên sử dụng TypeReferencevới convertValue().

final ObjectMapper mapper = new ObjectMapper();
final MyPojo<MyGenericType> pojo = mapper.convertValue(map, new TypeReference<MyPojo<MyGenericType>>() {});

Ngoài ra, bạn có thể sử dụng điều đó để chuyển đổi một pojo java.util.Maptrở lại.

final ObjectMapper mapper = new ObjectMapper();
final Map<String, Object> map = mapper.convertValue(pojo, new TypeReference<Map<String, Object>>() {});

2

Tôi đã thử nghiệm cả Jackson và BeanUtils và phát hiện ra rằng BeanUtils nhanh hơn nhiều.
Trong máy của tôi (Windows8.1, JDK1.7) tôi đã nhận được kết quả này.

BeanUtils t2-t1 = 286
Jackson t2-t1 = 2203


public class MainMapToPOJO {

public static final int LOOP_MAX_COUNT = 1000;

public static void main(String[] args) {
    Map<String, Object> map = new HashMap<>();
    map.put("success", true);
    map.put("data", "testString");

    runBeanUtilsPopulate(map);

    runJacksonMapper(map);
}

private static void runBeanUtilsPopulate(Map<String, Object> map) {
    long t1 = System.currentTimeMillis();
    for (int i = 0; i < LOOP_MAX_COUNT; i++) {
        try {
            TestClass bean = new TestClass();
            BeanUtils.populate(bean, map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    long t2 = System.currentTimeMillis();
    System.out.println("BeanUtils t2-t1 = " + String.valueOf(t2 - t1));
}

private static void runJacksonMapper(Map<String, Object> map) {
    long t1 = System.currentTimeMillis();
    for (int i = 0; i < LOOP_MAX_COUNT; i++) {
        ObjectMapper mapper = new ObjectMapper();
        TestClass testClass = mapper.convertValue(map, TestClass.class);
    }
    long t2 = System.currentTimeMillis();
    System.out.println("Jackson t2-t1 = " + String.valueOf(t2 - t1));
}}

5
Sự khác biệt là: Jackson có một khung chuyển đổi toàn bộ với nó. ví dụ: Mapchứa map.put("data","2016-06-26")TestClasscó một trường private LocalDate data;, sau đó Jackson sẽ có thể hoàn thành công việc, trong khi BeanUtils sẽ thất bại.
Benjamin M

6
Tôi nghe nói rằng việc tạo ObjectMappercá thể là một quá trình tiêu tốn thời gian / tài nguyên và nên sử dụng lại một cá thể ánh xạ thay vì tạo lại nó mỗi lần. Tôi nghĩ sẽ tốt hơn nếu lấy nó ra khỏi bản thử nghiệm
Mixaz

3
không phải là một thử nghiệm công bằng, vì BeanUtils có thể lưu trữ bộ đệm sau lần lặp đầu tiên, trong khi ObjectMapper không bao giờ có cơ hội.
Lucas Ross

1

Những câu trả lời cung cấp cho đến nay sử dụng Jackson rất tốt, nhưng bạn vẫn có thể có một util chức năng để giúp bạn chuyển đổi khác nhau POJOs như sau:

    public static <T> T convert(Map<String, Object> aMap, Class<T> t) {
        try {
            return objectMapper
                    .convertValue(aMap, objectMapper.getTypeFactory().constructType(t));
        } catch (Exception e) {
            log.error("converting failed! aMap: {}, class: {}", getJsonString(aMap), t.getClass().getSimpleName(), e);
        }
        return null;
    }

0

chuyển đổi Map thành ví dụ POJO. Chú ý khóa Map chứa gạch chân và biến trường là bướu.

Người dùng. Lớp POJO

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class User {
    @JsonProperty("user_name")
    private String userName;
    @JsonProperty("pass_word")
    private String passWord;
}

App. Class kiểm tra ví dụ

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;

public class App {
    public static void main(String[] args) {
        Map<String, String> info = new HashMap<>();
        info.put("user_name", "Q10Viking");
        info.put("pass_word", "123456");

        ObjectMapper mapper = new ObjectMapper();
        User user = mapper.convertValue(info, User.class);

        System.out.println("-------------------------------");
        System.out.println(user);
    }
}
/**output
-------------------------------
User(userName=Q10Viking, passWord=123456)
 */

0

@Hamedz nếu sử dụng nhiều dữ liệu, sử dụng Jackson để chuyển đổi dữ liệu ánh sáng, sử dụng apache ... TestCase:

import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; public class TestPerf { public static final int LOOP_MAX_COUNT = 1000; public static void main(String[] args) { Map<String, Object> map = new HashMap<>(); map.put("success", true); map.put("number", 1000); map.put("longer", 1000L); map.put("doubler", 1000D); map.put("data1", "testString"); map.put("data2", "testString"); map.put("data3", "testString"); map.put("data4", "testString"); map.put("data5", "testString"); map.put("data6", "testString"); map.put("data7", "testString"); map.put("data8", "testString"); map.put("data9", "testString"); map.put("data10", "testString"); runBeanUtilsPopulate(map); runJacksonMapper(map); } private static void runBeanUtilsPopulate(Map<String, Object> map) { long t1 = System.currentTimeMillis(); for (int i = 0; i < LOOP_MAX_COUNT; i++) { try { TestClass bean = new TestClass(); BeanUtils.populate(bean, map); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } long t2 = System.currentTimeMillis(); System.out.println("BeanUtils t2-t1 = " + String.valueOf(t2 - t1)); } private static void runJacksonMapper(Map<String, Object> map) { long t1 = System.currentTimeMillis(); for (int i = 0; i < LOOP_MAX_COUNT; i++) { ObjectMapper mapper = new ObjectMapper(); TestClass testClass = mapper.convertValue(map, TestClass.class); } long t2 = System.currentTimeMillis(); System.out.println("Jackson t2-t1 = " + String.valueOf(t2 - t1)); } @Data @AllArgsConstructor @NoArgsConstructor public static class TestClass { private Boolean success; private Integer number; private Long longer; private Double doubler; private String data1; private String data2; private String data3; private String data4; private String data5; private String data6; private String data7; private String data8; private String data9; private String data10; } }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.