Konvertieren Sie eine Map <String, String> in ein POJO

183

Ich habe mir Jackson angesehen, aber anscheinend müsste ich die Map in JSON und dann den resultierenden JSON in POJO konvertieren.

Gibt es eine Möglichkeit, eine Karte direkt in ein POJO umzuwandeln?

user86834
quelle

Antworten:

354

Das können Sie auch mit Jackson erreichen. (und es scheint bequemer zu sein, da Sie überlegt haben, Jackson zu verwenden).

Verwenden Sie ObjectMapperdie convertValueMethode:

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

Keine Notwendigkeit, in JSON-Zeichenfolge oder etwas anderes zu konvertieren; Die direkte Konvertierung erfolgt viel schneller.

Jongwook Choi
quelle
8
Sie müssen diese Bibliothek einschließen, um compile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
ObjectMapper
5
Die Verwendung von convertValue ist die richtige Antwort, aber erstellen Sie nicht jedes Mal eine ObjectMapper-Instanz. Es ist teuer zu erstellen und threadsicher, also erstellen Sie eine und zwischenspeichern Sie sie irgendwo.
Lichtung
1
Wissen Sie, wie man das Gegenteil macht - oder wie man ein Objekt in eine Map <String, Object> konvertiert?
anon58192932
2
@RaduSimionescu Haben Sie herausgefunden, wie Sie Objekte mit verschachtelten Karten / Listen in eine Map<String, Object>Instanz konvertieren können ?
anon58192932
@ anon58192932 es funktioniert, wenn Sie dieser Antwort folgen. Ich habe mich nur mit einigen seltsamen Objekten befasst, die Listen als Karten modellierten und bei der Serialisierung unerwartete Ergebnisse erzielten. aber das war ein anderes Problem, nichts mit Jackson zu tun
Radu Simionescu
59

Eine Lösung mit Gson :

Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(map);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);
AlikElzin-Kilaka
quelle
1
Was wird das umgekehrt sein
Prabs
2
@ Prabs - Das Gegenteil wäre gson.toJson ()
AlikElzin-kilaka
Sie müssen die Karte nicht in json konvertieren. map.toString () ist genug. Gson gson = new Gson (); MyPojo pojo = gson.fromJson (map.toString (), MyPojo.class);
Esakkiappan .E
@ Esakkiappan.E, warum wird Ihrer Meinung map.toString()nach die richtige Zeichenfolge bereitgestellt ? Eine Implementierung von toString()garantiert kein bestimmtes Format.
AlikElzin-kilaka vor
4

Ja, es ist definitiv möglich, die Zwischenkonvertierung in JSON zu vermeiden. Mit einem Deep-Copy-Tool wie Dozer können Sie die Karte direkt in ein POJO konvertieren. Hier ist ein vereinfachtes Beispiel:

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

Beispiel für einen Konvertierungscode:

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

Ausgabe:

MyPojo [ID = 5, Name = Bob, Alter = 23, Ersparnis = 2500,39]

Hinweis: Wenn Sie Ihre Quellzuordnung in a ändern Map<String, Object>, können Sie beliebig tief verschachtelte Eigenschaften kopieren (wobei Map<String, String>Sie nur eine Ebene erhalten).

Wahrnehmung
quelle
1
Wie können Sie eine "tiefe Kopie" von Map nach POJO erstellen? Angenommen, Sie haben eine Benutzerklasse, die eine Adressklasse kapselt, und die Zuordnung hat einen Schlüssel wie "address.city", "address.zip". Diese müssen User.Address.City und User.Address.Zip zugeordnet werden ? Es scheint den Punkt in der Map-Taste nicht automatisch als Unterebene des Objektdiagramms zu interpretieren.
Szxnyc
3

Wenn Sie generische Typen in Ihrer Klasse haben, sollten Sie TypeReferencemit verwenden convertValue().

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

Sie können das auch verwenden, um ein Pojo in java.util.MapBack umzuwandeln .

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

Ich habe sowohl Jackson als auch BeanUtils getestet und festgestellt, dass BeanUtils viel schneller ist.
Auf meinem Computer (Windows8.1, JDK1.7) habe ich dieses Ergebnis erhalten.

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
quelle
5
Der Unterschied ist: Jackson hat ein ganzes Framework für die Typkonvertierung. zB Mapenthält map.put("data","2016-06-26")und TestClasshat ein Feld private LocalDate data;, dann wäre Jackson in der Lage, Dinge zu erledigen, während BeanUtils fehlschlagen wird.
Benjamin M
6
Ich habe gehört, dass das Erstellen einer ObjectMapperInstanz ein zeit- und ressourcenintensiver Prozess ist, und es wird empfohlen, eine Mapper-Instanz erneut zu verwenden, anstatt sie jedes Mal neu zu erstellen. Ich denke, es wäre besser, es aus dem Test-Lop
herauszunehmen
3
Kein fairer Test, da BeanUtils nach der ersten Iteration zwischenspeichern kann, während ObjectMapper niemals die Chance erhält.
Lucas Ross
1

Die Antworten, die Jackson bisher gegeben hat, sind so gut, aber Sie könnten trotzdem eine Util- Funktion haben, die Ihnen hilft verschiedene POJOs wie folgt konvertieren können :

    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;
    }
Gehört
quelle
0

Beispiel "Map in POJO konvertieren". Beachten Sie, dass der Map-Schlüssel Unterstreichungen enthält und die Feldvariable "Buckel" ist.

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

Die App.class testet das Beispiel

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

@Hamedz Wenn Sie viele Daten verwenden, verwenden Sie Jackson, um Lichtdaten zu konvertieren, verwenden Sie 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
quelle