So konvertieren Sie eine JSON-Zeichenfolge mit Jackson JSON in eine Map <String, String>

183

Ich versuche so etwas zu machen, aber es funktioniert nicht:

Map<String, String> propertyMap = new HashMap<String, String>();

propertyMap = JacksonUtils.fromJSON(properties, Map.class);

Aber die IDE sagt:

Deaktivierte Zuordnung Map to Map<String,String>

Was ist der richtige Weg, um dies zu tun? Ich verwende Jackson nur, weil dies bereits im Projekt verfügbar ist. Gibt es eine native Java-Methode zum Konvertieren in / von JSON?

In PHP würde ich einfach json_decode($str)und ich würde ein Array zurückbekommen. Ich brauche hier im Grunde das Gleiche.

adamJLev
quelle
Woher kommt die Klasse JacksonUtils? Ich sehe es in keiner der Jackson-Veröffentlichungen.
Rob Heiser
Es ist unser Wrapper für Jackson, der einige der JsonFactory- und ObjectMapper-Aufgaben erledigt, die Sie erledigen müssen.
AdamJLev
1
Das Problem ist also, dass JacksonUtils.fromJSON () nicht deklariert wird, um Map <String, String> zurückzugeben, sondern nur Map.
Rob Heiser
7
Übrigens, weisen Sie dort in der ersten Zeile keine neue HashMap zu: das wird ignoriert. Ich nehme nur den Anruf entgegen.
StaxMan
Der Titel hat nichts mit dem beschriebenen Problem zu tun, das mit der untypisierten Sammlung zu tun hat. Die Antwort unten ist die richtige Antwort auf das, was Sie wirklich zu fragen versucht haben.
Jukka Dahlbom

Antworten:

310

Ich habe folgenden Code:

public void testJackson() throws IOException {  
    ObjectMapper mapper = new ObjectMapper(); 
    File from = new File("albumnList.txt"); 
    TypeReference<HashMap<String,Object>> typeRef 
            = new TypeReference<HashMap<String,Object>>() {};

    HashMap<String,Object> o = mapper.readValue(from, typeRef); 
    System.out.println("Got " + o); 
}   

Es liest aus einer Datei, mapper.readValue()akzeptiert aber auch eine InputStreamund Sie können eine InputStreamaus einer Zeichenfolge erhalten, indem Sie Folgendes verwenden:

new ByteArrayInputStream(astring.getBytes("UTF-8")); 

In meinem Blog gibt es ein bisschen mehr Erklärungen zum Mapper .

djna
quelle
2
@ Suraj, es ist gemäß der Dokumentation, und ich stimme zu, dass ich die Formulierung nicht aus den ersten Prinzipien hätte ableiten können. Es ist nicht so seltsam, zu zeigen, dass Java komplexer ist, als wir vielleicht denken.
DJNA
1
Krige: Ich dachte, das Schwierigste wäre, den Mapper zum Laufen zu bringen, aber ich habe den Hinweis hinzugefügt, wie man die Technik auf eine Saite
anwendet
2
Ein kleiner Kommentar: Die erste Erstellungszeile JsonFactorywird nicht benötigt. ObjectMapperkann es automatisch selbst erstellen.
StaxMan
1
@djna das Poster angefragt Map<String, String>und du hast zur Verfügung gestellt Map<String, Object>.
anon58192932
Um die Karte als Zeichenfolge zu schreiben, können Siemapper.writeValueAsString(hashmap)
Zaheer
53

Versuchen Sie es TypeFactory. Hier ist der Code für Jackson JSON (2.8.4).

Map<String, String> result;
ObjectMapper mapper;
TypeFactory factory;
MapType type;

factory = TypeFactory.defaultInstance();
type    = factory.constructMapType(HashMap.class, String.class, String.class);
mapper  = new ObjectMapper();
result  = mapper.readValue(data, type);

Hier ist der Code für eine ältere Version von Jackson JSON.

Map<String, String> result = new ObjectMapper().readValue(
    data, TypeFactory.mapType(HashMap.class, String.class, String.class));
Ning Sun.
quelle
38
TypeFactory.mapType (...) ist jetzt veraltet. Versuchen Sie Folgendes: new TypeReference <HashMap <String, String >> () {}
Cyber-Mönch
2
@ cyber-monk Das beseitigt die Warnungen, überprüft aber nicht die Typen.
David Moles
26

Die Warnung, die Sie erhalten, erfolgt durch den Compiler, nicht durch die Bibliothek (oder die Dienstprogrammmethode).

Der einfachste Weg, Jackson direkt zu verwenden, wäre:

HashMap<String,Object> props;

// src is a File, InputStream, String or such
props = new ObjectMapper().readValue(src, new TypeReference<HashMap<String,Object>>() {});
// or:
props = (HashMap<String,Object>) new ObjectMapper().readValue(src, HashMap.class);
// or even just:
@SuppressWarnings("unchecked") // suppresses typed/untype mismatch warnings, which is harmless
props = new ObjectMapper().readValue(src, HashMap.class);

Die von Ihnen aufgerufene Dienstprogrammmethode führt wahrscheinlich nur etwas Ähnliches aus.

StaxMan
quelle
OP gefragt Map<String, String>und Sie haben zur Verfügung gestellt Map<String, Object>.
anon58192932
18
ObjectReader reader = new ObjectMapper().readerFor(Map.class);

Map<String, String> map = reader.readValue("{\"foo\":\"val\"}");

Beachten Sie, dass die readerInstanz Thread-sicher ist.

dpetruha
quelle
@dpetruha OP gefragt Map<String, String>und Sie haben zur Verfügung gestellt Map<String, Object>.
anon58192932
10

Konvertieren von String in JSON Map:

Map<String,String> map = new HashMap<String,String>();

ObjectMapper mapper = new ObjectMapper();

map = mapper.readValue(string, HashMap.class);
Raja
quelle
4
Das Obige führt immer noch zu Type safety: The expression of type HashMap needs unchecked conversion to conform to Map<String,String>. Während dies mit @SuppressWarningsAnmerkungen unterdrückt werden kann , würde ich empfehlen, TypeReferencezuerst oder als nächstes Casting zu verwenden, wie von Staxman
Karthic Raghupathi
1
Um die Typensicherheitswarnung zu entfernen, können Sie sie verwenden map = mapper.readValue(string, map.getClass());- vorausgesetzt, Sie haben die Karte instanziiert, wie dies hier der Fall ist.
MJV
Wenn der Typ von var Map <Integer, String> ist, ist es einfach nicht richtig, die Objektklasse abzurufen.
Jiayu Wang
5
JavaType javaType = objectMapper.getTypeFactory().constructParameterizedType(Map.class, Key.class, Value.class);
Map<Key, Value> map=objectMapper.readValue(jsonStr, javaType);

Ich denke, das wird dein Problem lösen.

JackieZhi
quelle
1
in Java doc: @since 2.5 - wird aber wahrscheinlich in 2.7 oder 2.8 veraltet sein (nicht benötigt mit 2.7)
Al-Mothafar
3

Folgendes funktioniert für mich:

Map<String, String> propertyMap = getJsonAsMap(json);

wo getJsonAsMapist so definiert:

public HashMap<String, String> getJsonAsMap(String json)
{
    try
    {
        ObjectMapper mapper = new ObjectMapper();
        TypeReference<Map<String,String>> typeRef = new TypeReference<Map<String,String>>() {};
        HashMap<String, String> result = mapper.readValue(json, typeRef);

        return result;
    }
    catch (Exception e)
    {
        throw new RuntimeException("Couldnt parse json:" + json, e);
    }
}

Beachten Sie, dass dies wird fehlschlagen , wenn Sie untergeordnete Objekte in Ihrem json haben (weil sie keine sind String, sind sie eine andere HashMap), aber funktioniert , wenn Ihr json eine Schlüsselwert - Liste von Eigenschaften wie so ist:

{
    "client_id": "my super id",
    "exp": 1481918304,
    "iat": "1450382274",
    "url": "http://www.example.com"
}
Brad Parks
quelle
3

Verwenden von Google Gson

Warum nicht Googles Gson verwenden, wie hier erwähnt ?

Sehr unkompliziert und hat den Job für mich gemacht:

HashMap<String,String> map = new Gson().fromJson( yourJsonString, new TypeToken<HashMap<String, String>>(){}.getType());
Loukan ElKadi
quelle
1
Einverstanden, die Welt hat sich weiterentwickelt, Gson ist viel, viel einfacher zu bedienen.
DJNA
1

Hier ist die generische Lösung für dieses Problem.

public static <K extends Object, V extends Object> Map<K, V> getJsonAsMap(String json, K key, V value) {
    try {
      ObjectMapper mapper = new ObjectMapper();
      TypeReference<Map<K, V>> typeRef = new TypeReference<Map<K, V>>() {
      };
      return mapper.readValue(json, typeRef);
    } catch (Exception e) {
      throw new RuntimeException("Couldnt parse json:" + json, e);
    }
  }

Hoffe, eines Tages würde jemand darüber nachdenken, eine util-Methode zu erstellen, um sie in einen beliebigen Schlüssel- / Werttyp der Karte zu konvertieren, daher diese Antwort :)

NameNotFoundException
quelle
-1

Ich wollte nur eine Kotlin-Antwort geben

val propertyMap = objectMapper.readValue<Map<String,String>>(properties, object : TypeReference<Map<String, String>>() {})
Dustin
quelle
hmmm, ich bin mir nicht sicher, warum dies abgelehnt wurde. Diese Linie funktioniert nicht nur für mich, sie gibt auch den Schlüssel, um es richtig zu machen. Durch Ersetzen von Map <String, String> durch einen anderen gewünschten Typ konvertiert der Mapper den String in eine komplexe Sammlung wie List <MyObject> oder List <Map <String, MyObject >>
Dustin