Come convertire una stringa JSON in una mappa <String, String> con Jackson JSON


185

Sto provando a fare qualcosa del genere ma non funziona:

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

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

Ma l'IDE dice:

Assegnazione non selezionata Map to Map<String,String>

Qual è il modo giusto per farlo? Sto solo usando Jackson perché è ciò che è già disponibile nel progetto, esiste un modo Java nativo per convertire da / a JSON?

In PHP avrei semplicemente json_decode($str)e avrei recuperato un array. Ho sostanzialmente bisogno della stessa cosa qui.


Da dove viene la classe JacksonUtils? Non lo vedo in nessuna delle versioni di Jackson.
Rob Heiser,

È il nostro wrapper per Jackson, gestisce alcune delle cose di JsonFactory e ObjectMapper che devi fare.
adamJLev

1
Quindi, il problema è che JacksonUtils.fromJSON () non viene dichiarato per restituire Map <String, String>, ma solo Map.
Rob Heiser,

7
A proposito, non assegnare la nuova HashMap lì sulla prima riga: questo viene ignorato. Sto solo valutando la chiamata.
StaxMan,

Il titolo non ha nulla a che fare con il problema descritto, che riguarda la raccolta non tipizzata. La risposta di seguito è la risposta corretta a ciò che hai veramente cercato di chiedere.
Jukka Dahlbom,

Risposte:


313

Ho il seguente codice:

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

Sta leggendo da un file, ma mapper.readValue()accetterà anche un InputStreame puoi ottenere un InputStreamda una stringa usando quanto segue:

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

C'è un po 'più di spiegazione sul mapper sul mio blog .


2
@Suraj, è come nella documentazione, e sono d'accordo che non avrei potuto dedurre la formulazione dai primi principi. Non è così strano come mostrare che Java è più complesso di quanto potremmo pensare.
djna,

1
Krige: Pensavo che la cosa più difficile fosse far funzionare il mapper, ma ho aggiunto la nota su come applicare la tecnica a una stringa
djna,

2
Un commento minore: la prima linea di creazione JsonFactorynon è necessaria. ObjectMapperpuò crearlo automaticamente da solo.
StaxMan,

1
@djna il poster ha richiesto Map<String, String>e hai fornito Map<String, Object>.
anon58192932

Per scrivere la Mappa come una stringa, puoi farlomapper.writeValueAsString(hashmap)
Zaheer,

53

Prova TypeFactory. Ecco il codice per 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);

Ecco il codice per una versione precedente di Jackson JSON.

Map<String, String> result = new ObjectMapper().readValue(
    data, TypeFactory.mapType(HashMap.class, String.class, String.class));

38
TypeFactory.mapType (...) è ora deprecato, prova questo: new TypeReference <HashMap <String, String >> () {}
cyber-monk

2
@ cyber-monk che elimina gli avvisi, ma in realtà non controlla i tipi.
David Moles,

26

L'avviso che ricevi viene fatto dal compilatore, non dalla libreria (o dal metodo di utilità).

Il modo più semplice di utilizzare Jackson direttamente sarebbe:

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

Il metodo di utilità che chiami probabilmente fa qualcosa di simile a questo.


OP richiesto Map<String, String>e hai fornito Map<String, Object>.
anon58192932

18
ObjectReader reader = new ObjectMapper().readerFor(Map.class);

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

Si noti che l' readeristanza è Thread Safe.


@dpetruha OP ha chiesto Map<String, String>e hai fornito Map<String, Object>.
anon58192932

10

Conversione da String a JSON Map:

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

ObjectMapper mapper = new ObjectMapper();

map = mapper.readValue(string, HashMap.class);

4
Quanto sopra risulta ancora Type safety: The expression of type HashMap needs unchecked conversion to conform to Map<String,String>. Mentre questo può essere soppresso con l' @SuppressWarningsannotazione, consiglierei di usare TypeReferenceprima o il casting successivo come menzionato da Staxman
Karthic Raghupathi il

1
Per sbarazzarti dell'avvertimento di sicurezza del tipo, puoi usare map = mapper.readValue(string, map.getClass());, dato che hai istanziato la mappa, come nel caso qui.
MJV

se il tipo di var è Mappa <Intero, Stringa>, Ottieni la classe oggetto non è corretta.
Jiayu Wang,

5
JavaType javaType = objectMapper.getTypeFactory().constructParameterizedType(Map.class, Key.class, Value.class);
Map<Key, Value> map=objectMapper.readValue(jsonStr, javaType);

penso che questo risolverà il tuo problema.


1
in java doc: @since 2.5 - ma probabilmente sarà deprecato in 2.7 o 2.8 (non necessario con 2.7)
Al-Mothafar,

3

Per me funziona quanto segue:

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

dove getJsonAsMapè definito così:

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

Si noti che questo avrà esito negativo se si dispone di oggetti figlio in JSON (perché non sono una String, sono un'altra HashMap), ma funzionano se il JSON è un elenco di valori chiave delle proprietà in questo modo:

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

3

Utilizzando Google Gson

Perché non utilizzare Gson di Google come indicato qui ?

Molto semplice e ha fatto il lavoro per me:

HashMap<String,String> map = new Gson().fromJson( yourJsonString, new TypeToken<HashMap<String, String>>(){}.getType());

1
D'accordo, il mondo è passato, Gson è molto, molto più facile da usare.
djna

1

Ecco la soluzione generica a questo problema.

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

Spero che un giorno qualcuno pensi di creare un metodo util per convertire in qualsiasi tipo di chiave / valore della mappa, quindi questa risposta :)


-1

volevo solo dare una risposta a Kotlin

val propertyMap = objectMapper.readValue<Map<String,String>>(properties, object : TypeReference<Map<String, String>>() {})

hmmm, non sono sicuro del perché questo sia stato sottoposto a downgrade. Questa linea non solo funziona per me, ma fornisce anche la chiave per farlo nel modo giusto. Sostituendo Mappa <String, String> con un diverso tipo desiderato, il mapper convertirà la stringa in qualsiasi raccolta complessa, come List <MyObject> o List <Map <String, MyObject >>
Dustin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.