Cách chuyển đổi chuỗi JSON thành Bản đồ <Chuỗi, Chuỗi> bằng Jackson JSON


183

Tôi đang cố gắng làm một cái gì đó như thế này nhưng nó không hoạt động:

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

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

Nhưng IDE nói:

Bài tập không được kiểm tra Map to Map<String,String>

Cách đúng đắn để làm điều này là gì? Tôi chỉ sử dụng Jackson vì đó là những gì đã có sẵn trong dự án, có cách chuyển đổi Java gốc / từ JSON không?

Trong PHP tôi chỉ đơn giản là json_decode($str)tôi sẽ lấy lại một mảng. Tôi cần cơ bản điều tương tự ở đây.


Lớp JacksonUtils đến từ đâu? Tôi không thấy nó trong bất kỳ bản phát hành nào của Jackson.
Rob Heiser

Đó là trình bao bọc của chúng tôi cho Jackson, xử lý một số công cụ JsonFactory và ObjectMapper mà bạn phải làm.
adamJLev

1
Vì vậy, vấn đề là JacksonUtils.fromJSON () không được khai báo để trả về Map <String, String>, mà chỉ là Map.
Rob Heiser

7
Btw, đừng gán HashMap mới ở dòng đầu tiên: bị bỏ qua. Chỉ cần khẳng định cuộc gọi.
Staxman

Tiêu đề không liên quan gì đến vấn đề được mô tả của bạn, liên quan đến bộ sưu tập chưa được chỉnh sửa. Câu trả lời dưới đây là câu trả lời chính xác cho những gì bạn thực sự cố gắng hỏi.
Jukka Dahlbom

Câu trả lời:


310

Tôi đã nhận được mã sau đây:

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

Nó đang đọc từ một tệp, nhưng mapper.readValue()cũng sẽ chấp nhận InputStreamvà bạn có thể lấy InputStreamtừ một chuỗi bằng cách sử dụng như sau:

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

Có một chút giải thích về trình ánh xạ trên blog của tôi .


2
@Suraj, theo tài liệu này, và tôi đồng ý rằng tôi sẽ không thể suy ra công thức từ các nguyên tắc đầu tiên. Nó không quá kỳ lạ khi cho thấy Java phức tạp hơn chúng ta tưởng.
djna

1
Krige: Tôi nghĩ rằng một chút khó khăn đã khiến người vẽ bản đồ đi, nhưng tôi đã thêm ghi chú về cách áp dụng kỹ thuật này vào chuỗi
djna

2
Một nhận xét nhỏ: dòng đầu tiên của việc tạo JsonFactorylà không cần thiết. ObjectMappercó thể tự động tạo nó.
StaxMan

1
@djna người đăng yêu cầu Map<String, String>và bạn đã cung cấp Map<String, Object>.
anon58192932

Để viết Bản đồ dưới dạng chuỗi bạn có thể làmmapper.writeValueAsString(hashmap)
Zaheer

53

Hãy thử TypeFactory. Đây là mã cho 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);

Đây là mã cho phiên bản cũ hơn của Jackson JSON.

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

38
TypeFactory.mapType (...) hiện không được chấp nhận, hãy thử điều này: TypeReference mới <HashMap <String, String >> () {}
cyber-monk

2
@ cyber-monk Điều đó được loại bỏ các cảnh báo, nhưng thực tế không kiểm tra các loại.
David Moles

26

Cảnh báo bạn nhận được được thực hiện bởi trình biên dịch, không phải bởi thư viện (hoặc phương thức tiện ích).

Cách đơn giản nhất sử dụng Jackson trực tiếp sẽ là:

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

Phương pháp tiện ích mà bạn gọi có lẽ chỉ cần làm một cái gì đó tương tự như thế này.


OP đã yêu cầu Map<String, String>và bạn đã cung cấp Map<String, Object>.
anon58192932

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

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

Lưu ý rằng readerví dụ là Thread Safe.


@dpetruha OP đã yêu cầu Map<String, String>và bạn đã cung cấp Map<String, Object>.
anon58192932

10

Chuyển đổi từ Chuỗi sang Bản đồ JSON:

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

ObjectMapper mapper = new ObjectMapper();

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

4
Các kết quả trên vẫn có kết quả Type safety: The expression of type HashMap needs unchecked conversion to conform to Map<String,String>. Mặc dù điều này có thể được loại bỏ bằng @SuppressWarningschú thích, tôi khuyên bạn nên sử dụng TypeReferenceđầu tiên hoặc chọn tiếp theo như được đề cập bởi Staxman
Karthic Raghupathi

1
Để thoát khỏi cảnh báo an toàn loại, bạn có thể sử dụng map = mapper.readValue(string, map.getClass());- với điều kiện bạn đã khởi tạo bản đồ, như trường hợp ở đây.
MJV

nếu loại var là Map <Integer, String>, chỉ cần lấy lớp đối tượng là không đúng.
Jiayu Wang

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

tôi nghĩ rằng điều này sẽ giải quyết vấn đề của bạn.


1
trong tài liệu java: @since 2.5 - nhưng có thể sẽ không dùng nữa trong 2.7 hoặc 2.8 (không cần thiết với 2.7)
Al-Mothafar

3

Các công việc sau đây cho tôi:

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

nơi getJsonAsMapđược định nghĩa như vậy:

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

Lưu ý rằng điều này sẽ thất bại nếu bạn có các đối tượng con trong json của mình (vì chúng không phải là String, chúng là một đối tượng khác HashMap), nhưng sẽ hoạt động nếu json của bạn là danh sách giá trị chính của các thuộc tính như vậy:

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

3

Sử dụng Google Gson

Tại sao không sử dụng Gson của Google như được đề cập ở đây ?

Rất thẳng về phía trước và đã làm công việc cho tôi:

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

1
Đồng ý, thế giới đã chuyển sang, Gson dễ sử dụng hơn nhiều.
djna

1

Đây là giải pháp chung cho vấn đề này.

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

Hy vọng một ngày nào đó ai đó sẽ nghĩ sẽ tạo ra một phương thức sử dụng để chuyển đổi sang bất kỳ loại Khóa / giá trị nào của Bản đồ do đó trả lời :)


-1

chỉ muốn đưa ra một câu trả lời của Kotlin

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

hmmm, không chắc tại sao điều này bị hạ cấp. Dòng này không chỉ làm việc cho tôi, nó còn cung cấp chìa khóa để thực hiện đúng cách. Bằng cách thay thế Map <String, String> bằng một loại mong muốn khác, trình ánh xạ sẽ chuyển đổi chuỗi thành bất kỳ bộ sưu tập phức tạp nào, như List <MyObject> hoặc List <Map <String, MyObject >>
Dustin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.