Cara mengonversi string JSON ke Peta <String, String> dengan Jackson JSON

185

Saya mencoba melakukan sesuatu seperti ini tetapi tidak berhasil:

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

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

Namun IDE mengatakan:

Tugas tidak dicentang Map to Map<String,String>

Apa cara yang benar untuk melakukan ini? Saya hanya menggunakan Jackson karena itulah yang sudah tersedia dalam proyek ini, apakah ada cara Java asli untuk mengkonversi ke / dari JSON?

Dalam PHP saya hanya json_decode($str)dan saya akan kembali array. Saya pada dasarnya membutuhkan hal yang sama di sini.

adamJLev
sumber
Di mana kelas JacksonUtils berasal? Saya tidak melihatnya di salah satu rilis Jackson.
Rob Heiser
Ini adalah pembungkus kami untuk Jackson, menangani beberapa hal JsonFactory dan ObjectMapper yang harus Anda lakukan.
adamJLev
1
Jadi, masalahnya adalah bahwa JacksonUtils.fromJSON () tidak dideklarasikan untuk mengembalikan Map <String, String>, tetapi hanya Map.
Rob Heiser
7
Btw, jangan tetapkan HashMap baru di sana pada baris pertama: itu akan diabaikan. Hanya menerima telepon.
StaxMan
Judul tidak ada hubungannya dengan masalah yang Anda gambarkan, yang terkait dengan koleksi yang tidak diketik. Jawaban di bawah adalah jawaban yang benar untuk apa yang sebenarnya Anda coba tanyakan.
Jukka Dahlbom

Jawaban:

313

Saya mendapat kode berikut:

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

Itu membaca dari file, tetapi mapper.readValue()juga akan menerima InputStreamdan Anda dapat memperoleh InputStreamdari string dengan menggunakan yang berikut:

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

Ada sedikit penjelasan tentang mapper di blog saya .

djna
sumber
2
@ Suraj, ini sesuai dengan dokumentasi, dan saya setuju saya tidak akan dapat menyimpulkan rumusan dari prinsip pertama. Tidak terlalu aneh untuk menunjukkan bahwa Jawa lebih kompleks dari yang kita kira.
djna
1
Krige: Saya pikir sedikit kesulitan membuat mapper berjalan, tapi saya telah menambahkan catatan tentang bagaimana menerapkan teknik ke string
djna
2
Satu komentar kecil: baris pertama pembuatan JsonFactorytidak diperlukan. ObjectMapperdapat membuatnya secara otomatis sendiri.
StaxMan
1
@jj poster yang diminta Map<String, String>dan Anda berikan Map<String, Object>.
anon58192932
Untuk menulis Peta sebagai string yang dapat Anda lakukanmapper.writeValueAsString(hashmap)
Zaheer
53

Coba TypeFactory. Berikut kode untuk 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);

Berikut kode untuk Jackson JSON versi yang lebih lama.

Map<String, String> result = new ObjectMapper().readValue(
    data, TypeFactory.mapType(HashMap.class, String.class, String.class));
Ning Sun
sumber
38
TypeFactory.mapType (...) sekarang sudah tidak digunakan lagi, coba ini: TypeReference baru <HashMap <String, String >> () {}
cyber-monk
2
@ cyber-monk Itu menghilangkan peringatan, tetapi sebenarnya tidak memeriksa tipenya.
David Moles
26

Peringatan yang Anda dapatkan dilakukan oleh kompiler, bukan oleh perpustakaan (atau metode utilitas).

Cara paling mudah menggunakan Jackson secara langsung adalah:

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

Metode utilitas yang Anda panggil mungkin hanya melakukan sesuatu yang mirip dengan ini.

StaxMan
sumber
OP meminta Map<String, String>dan Anda telah menyediakan Map<String, Object>.
anon58192932
18
ObjectReader reader = new ObjectMapper().readerFor(Map.class);

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

Perhatikan bahwa readerinstance adalah Thread Safe.

dpetruha
sumber
@dpetruha OP meminta Map<String, String>dan Anda telah menyediakan Map<String, Object>.
anon58192932
10

Konversi dari String ke JSON Map:

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

ObjectMapper mapper = new ObjectMapper();

map = mapper.readValue(string, HashMap.class);
Raja
sumber
4
Di atas masih menghasilkan Type safety: The expression of type HashMap needs unchecked conversion to conform to Map<String,String>. Meskipun ini dapat ditekan dengan @SuppressWarningsanotasi, saya akan merekomendasikan menggunakan TypeReferencepertama atau casting selanjutnya seperti yang disebutkan oleh Staxman
Karthic Raghupathi
1
Untuk menghilangkan jenis peringatan keselamatan, Anda dapat menggunakan map = mapper.readValue(string, map.getClass());- mengingat bahwa Anda telah instantiated peta, seperti halnya di sini.
MJV
jika jenis var adalah Map <Integer, String>, Hanya mendapatkan kelas objek tidak benar.
Jiayu Wang
5
JavaType javaType = objectMapper.getTypeFactory().constructParameterizedType(Map.class, Key.class, Value.class);
Map<Key, Value> map=objectMapper.readValue(jsonStr, javaType);

Saya pikir ini akan menyelesaikan masalah Anda.

JackieZhi
sumber
1
dalam java doc: @since 2.5 - tetapi mungkin akan usang dalam 2.7 atau 2.8 (tidak diperlukan dengan 2.7)
Al-Mothafar
3

Berikut ini berfungsi untuk saya:

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

di mana getJsonAsMapdidefinisikan seperti ini:

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

Perhatikan bahwa ini akan gagal jika Anda memiliki objek anak di json Anda (karena mereka bukan a String, mereka yang lain HashMap), tetapi akan berfungsi jika json Anda adalah daftar nilai kunci dari properti seperti:

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

Menggunakan Google Gson

Mengapa tidak menggunakan Google Gson seperti yang disebutkan di sini ?

Sangat lurus ke depan dan melakukan pekerjaan untuk saya:

HashMap<String,String> map = new Gson().fromJson( yourJsonString, new TypeToken<HashMap<String, String>>(){}.getType());
Loukan ElKadi
sumber
1
Setuju, dunia telah bergerak, Gson jauh, lebih mudah digunakan.
djna
1

Ini adalah solusi umum untuk masalah ini.

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

Semoga suatu hari nanti seseorang akan berpikir untuk membuat metode util untuk mengkonversi ke jenis Kunci / nilai Peta maka jawaban ini :)

NameNotFoundException
sumber
-1

hanya ingin memberikan jawaban Kotlin

val propertyMap = objectMapper.readValue<Map<String,String>>(properties, object : TypeReference<Map<String, String>>() {})
Dustin
sumber
hmmm, tidak yakin mengapa ini diturunkan. Baris ini tidak hanya bekerja untuk saya, tetapi juga memberikan kunci untuk melakukannya dengan cara yang benar. Dengan mengganti Map <String, String> dengan tipe yang diinginkan berbeda, mapper akan mengubah string menjadi kumpulan kompleks, seperti List <MyObject>, atau List <Map <String, MyObject >>
Dustin