Bir Haritası <Dize, Dize> bir POJO'ya dönüştürme


186

Jackson'a bakıyordum, ama Harita'yı JSON'a ve sonra ortaya çıkan JSON'u POJO'ya dönüştürmek zorunda kalacağım gibi görünüyor.

Bir Haritayı doğrudan bir POJO'ya dönüştürmenin bir yolu var mı?

Yanıtlar:


355

Bunu Jackson ile de başarabilirsiniz. (ve jackson kullanmayı düşündüğünüzden beri daha rahat görünüyor).

Kullanım ObjectMapperbireyin convertValueyöntemi:

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

JSON dizesine veya başka bir şeye dönüştürmeye gerek yok; doğrudan dönüşüm çok daha hızlı yapar.


8
ObjectMappercompile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
Shajeel Afzal

5
ConvertValue kullanmak doğru cevaptır, ancak her seferinde bir ObjectMapper örneği oluşturmayın. Oluşturmak ve iş parçacığı açısından güvenli, bu yüzden bir tane oluşturun ve bir yerde önbellekleyin.
glade

1
tersini nasıl yapacağınızı veya bir nesneyi Haritaya <String, Object> dönüştürmeyi biliyor musunuz?
anon58192932

2
@RaduSimionescu, iç içe haritalara / listelere sahip nesneleri nasıl bir Map<String, Object>örneğe dönüştüreceğinizi anladınız mı?
anon58192932

@ anon58192932 bu yanıtı takip ederseniz çalışır. Listeleri harita olarak modelleyen ve serileştirme beklenmedik sonuçlar elde ederken bazı garip nesnelerle uğraşıyordum. ama bu başka bir konuydu, jackson ile ilgisi yok
Radu Simionescu

60

Gson ile bir çözüm :

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

1
tam tersi ne olacak
Prabs

2
@Prabs - Tam tersi gson.toJson ()
AlikElzin-kilaka

Haritayı json'a dönüştürmeye gerek yok. map.toString () yeterlidir. Gson gson = yeni Gson (); MyPojo pojo = gson.fromJson (map.toString (), MyPojo.class);
Esakkiappan .E

1
@ Esakkiappan.E, neden map.toString()doğru dizeyi sağlayacağınızı düşünüyorsunuz ? Öğesinin uygulanması toString()belirli bir biçimi garanti etmez.
AlikElzin-kilaka

4

Evet, JSON'a ara dönüşümden kaçınmak kesinlikle mümkündür. Dozer gibi bir derin kopyalama aracı kullanarak haritayı doğrudan bir POJO'ya dönüştürebilirsiniz. İşte basit bir örnek:

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

Örnek dönüşüm kodu:

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

Çıktı:

MyPojo [id = 5, ad = Bob, yaş = 23, tasarruf = 2500.39]

Not: Kaynak haritanızı bir ile değiştirirseniz, Map<String, Object>keyfi olarak derin yuvalanmış özelliklerin üzerine kopyalayabilirsiniz ( Map<String, String>yalnızca bir seviye alırsınız).


1
Haritadan POJO'ya nasıl "derin kopya" yapabilirsin? Örneğin, bir Address.class dosyasını kapsülleyen bir User.class dosyanız olduğunu ve haritanın "address.city", "address.zip" gibi bir anahtarı olduğunu ve bunların User.Address.City ve User.Address.Zip ile eşleşmeleri gerektiğini varsayalım ? Harita anahtarındaki noktayı nesne grafiğinin alt düzeyi olarak otomatik olarak yorumlamıyor gibi görünüyor.
szxnyc

4

Sınıfınızda jenerik türlerini varsa kullanmalısınız TypeReferenceile convertValue().

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

Ayrıca bir pojo java.util.Mapgeri geri dönüştürmek için kullanabilirsiniz .

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

2

Hem Jackson hem de BeanUtils'i test ettim ve BeanUtils'in çok daha hızlı olduğunu öğrendim.
Makinemde (Windows8.1, JDK1.7) bu sonucu aldım.

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
Fark şudur: Jackson'ın onunla birlikte tam bir dönüşüm çerçevesi vardır. Örneğin, Mapiçeren map.put("data","2016-06-26")ve TestClassbir alan vardır private LocalDate data;, o zaman Jackson BeanUtils başarısız olurken işleri halledebilir.
Benjamin M

6
ObjectMapperÖrnek oluşturmanın zaman / kaynak tüketen bir süreç olduğunu duydum ve her seferinde yeniden oluşturmak yerine bir eşleyici örneğinin yeniden kullanılması önerilir. Bence test
lopundan

3
BeanUtils ilk yinelemeden sonra önbellekleme yapabildiğinden, ObjectMapper'a hiçbir zaman şans verilmediği için adil bir test değil.
Lucas Ross

1

Şimdiye kadar Jackson kullanılarak sağlanan cevaplar iyiliği yüzden, ama yine de bir olabilir util yardımına işlevi size dönüştürmek farklı POJOaşağıdaki gibi s:

    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

Map'i POJO örneğine dönüştürün. Map tuşunun altını çizdiğini ve field değişkeninin kambur olduğunu unutmayın.

Kullanıcı. Sınıf 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 örneği

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 çok veri kullanırsa, hafif verileri dönüştürmek için Jackson'ı kullanın, apache kullanın ... 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; } }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.