Konversi Peta <String, String> ke POJO

186

Saya telah melihat Jackson, tetapi sepertinya saya harus mengubah Peta menjadi JSON, dan kemudian hasil JSON ke POJO.

Apakah ada cara untuk mengonversi Peta secara langsung ke POJO?

pengguna86834
sumber

Jawaban:

355

Nah, Anda juga bisa mencapainya dengan Jackson. (dan tampaknya lebih nyaman karena Anda mempertimbangkan untuk menggunakan jackson).

Gunakan ObjectMapper's convertValuemetode:

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

Tidak perlu mengkonversi ke string JSON atau yang lainnya; konversi langsung lebih cepat.

Jongwook Choi
sumber
8
Anda harus memasukkan perpustakaan ini untuk menggunakan ObjectMappercompile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
Shajeel Afzal
5
Menggunakan convertValue adalah jawaban yang tepat, tetapi jangan membuat instance ObjectMapper setiap saat. Membuat dan thread-safe itu mahal, jadi buat satu dan simpan di suatu tempat.
glade
1
apakah Anda tahu cara melakukan yang sebaliknya - atau cara mengonversi objek ke Peta <String, Object>?
anon58192932
2
@RaduSimionescu apakah Anda mengetahui cara mengkonversi objek dengan peta / daftar bersarang menjadi sebuah Map<String, Object>instance?
anon58192932
@ anon58192932 berfungsi jika Anda mengikuti jawaban ini. Saya hanya berurusan dengan beberapa objek aneh yang memodelkan daftar sebagai peta dan ketika serialisasi mendapatkan hasil yang tidak terduga. tapi itu masalah lain, tidak ada hubungannya dengan jackson
Radu Simionescu
60

Solusi dengan Gson :

Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(map);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);
AlikElzin-kilaka
sumber
1
apa yang akan menjadi sebaliknya
Prabs
2
@Prabs - Sebaliknya akan gson.toJson ()
AlikElzin-kilaka
Tidak perlu mengonversi peta ke json. map.toString () sudah cukup. Gson gson = Gson baru (); MyPojo pojo = gson.fromJson (map.toString (), MyPojo.class);
Esakkiappan .E
1
@ Esakkiappan.E, menurut Anda mengapa map.toString()memberikan string yang benar? Implementasi dari toString()tidak menjamin format tertentu.
AlikElzin-kilaka
4

Ya, sangat mungkin untuk menghindari konversi antara ke JSON. Menggunakan alat salin-dalam seperti Dozer Anda dapat mengkonversi peta langsung ke POJO. Ini adalah contoh sederhana:

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

Contoh kode konversi:

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

Keluaran:

MyPojo [id = 5, nama = Bob, usia = 23, tabungan = 2500,39]

Catatan: Jika Anda mengubah peta sumber Anda menjadi Map<String, Object>maka Anda dapat menyalin lebih dari properti bersarang mendalam (dengan Map<String, String>Anda hanya mendapatkan satu tingkat).

Persepsi
sumber
1
Bagaimana Anda bisa melakukan "salinan dalam" dari Peta ke POJO? Katakan misalnya Anda memiliki User.class yang merangkum Address.class dan peta memiliki kunci seperti "address.city", "address.zip" dan ini perlu dipetakan ke User.Address.City dan User.Address.Zip ? Tampaknya tidak secara otomatis menafsirkan titik di kunci Peta sebagai sub-level ke grafik objek.
szxnyc
4

jika Anda memiliki jenis generik di kelas Anda Anda harus menggunakan TypeReferencedengan convertValue().

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

Anda juga dapat menggunakannya untuk mengubah pojo menjadi java.util.Mapkembali.

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

Saya telah menguji Jackson dan BeanUtils dan menemukan bahwa BeanUtils jauh lebih cepat.
Di mesin saya (Windows8.1, JDK1.7) saya mendapat hasil ini.

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));
}}
Hamedz
sumber
5
Perbedaannya adalah: Jackson memiliki kerangka kerja konversi tipe keseluruhan dengan itu. misal Mapberisi map.put("data","2016-06-26")dan TestClassmemiliki bidang private LocalDate data;, maka Jackson akan bisa menyelesaikan sesuatu, sedangkan BeanUtils akan gagal.
Benjamin M
6
Saya mendengar bahwa membuat ObjectMapperinstance adalah proses yang menghabiskan waktu / sumber daya, dan disarankan untuk menggunakan kembali satu instance mapper daripada membuatnya lagi setiap kali. Saya pikir akan lebih baik untuk mengeluarkannya dari ujian
Mixaz
3
bukan tes yang adil, karena BeanUtils dapat melakukan cache setelah iterasi pertama, sedangkan ObjectMapper tidak pernah diberi kesempatan.
Lucas Ross
1

Jawaban yang diberikan sejauh ini menggunakan Jackson sangat baik, tetapi tetap Anda bisa memiliki fungsi util untuk membantu Anda mengonversi yang berbeda POJOsebagai berikut:

    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;
    }
Dengarkan
sumber
0

convert Map to POJO example.Perhatikan kunci Map berisi garis bawah dan variabel bidang adalah punuk.

User.class 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 menguji contoh ini

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)
 */
Q10Viking
sumber
0

@Hamedz jika menggunakan banyak data, gunakan Jackson untuk mengonversi data ringan, gunakan 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; } }
Fernando Roza
sumber