맵 <문자열, 문자열>을 POJO로 변환


185

잭슨을보고 있었지만 Map을 JSON으로 변환 한 다음 결과 JSON을 POJO로 변환해야합니다.

지도를 POJO로 직접 변환하는 방법이 있습니까?

답변:


355

음, 잭슨도 그렇게 할 수 있습니다. (그리고 잭슨 사용을 고려한 이후로 더 편안해 보입니다).

ObjectMapperconvertValue방법을 사용하십시오 .

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

JSON 문자열 또는 다른 것으로 변환 할 필요가 없습니다. 직접 변환은 훨씬 빠릅니다.


8
당신은 ObjectMapper 사용하려면이 라이브러리를 포함 할 필요가compile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
Shajeel 아프

5
convertValue를 사용하는 것이 정답이지만 매번 ObjectMapper 인스턴스를 만들지 마십시오. 작성하고 스레드로부터 안전하므로 비용이 많이 들며 어딘가에 캐시하십시오.
glade

1
반대로하는 방법 또는 객체를 Map <String, Object>로 변환하는 방법을 알고 있습니까?
anon58192932

2
@RaduSimionescu 중첩 된 맵 / 목록이있는 객체를 Map<String, Object>인스턴스 로 딥 변환하는 방법을 알아 냈 습니까?
anon58192932

@ anon58192932이 답변을 따르면 작동합니다. 목록으로 맵을 모델링하고 직렬화 할 때 예기치 않은 결과가 발생하는 이상한 객체를 처리했습니다. 그러나 그것은 또 다른 문제였습니다. 잭슨과는 아무 관련이 없습니다
Radu Simionescu

60

Gson 을 사용한 솔루션 :

Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(map);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);

1
그 반대는 무엇인가
Prabs

2
@Prabs-그 반대의 경우 gson.toJson ()
AlikElzin-kilaka

map을 json으로 변환 할 필요가 없습니다. map.toString ()으로 충분합니다. Gson gson = 새로운 Gson (); MyPojo pojo = gson.fromJson (map.toString (), MyPojo.class);
Esakkiappan .E

1
@ Esakkiappan.E, 왜 map.toString()올바른 문자열을 제공 한다고 생각 하십니까? 구현이 toString()특정 형식을 보장하지는 않습니다.
AlikElzin-kilaka

4

예, JSON으로의 중간 변환을 피할 수 있습니다. Dozer 와 같은 심도 복사 도구를 사용 하여지도를 POJO로 직접 변환 할 수 있습니다. 다음은 간단한 예입니다.

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

샘플 변환 코드 :

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

산출:

MyPojo [id = 5, 이름 = Bob, 나이 = 23, 저축 = 2500.39]

참고 : 소스 맵을로 변경 Map<String, Object>하면 임의로 깊은 중첩 속성을 복사 할 수 있습니다 ( Map<String, String>한 수준 만 가져옴).


1
Map에서 POJO로 "딥 카피"를 어떻게 할 수 있습니까? 예를 들어 Address.class를 캡슐화하는 User.class가 있고 맵에 "address.city", "address.zip"과 같은 키가 있으며 User.Address.City 및 User.Address.Zip에 맵핑해야한다고 가정하십시오. ? Map 키의 점을 객체 그래프의 하위 수준으로 자동 해석하지 않는 것 같습니다.
szxnyc

4

클래스에 제네릭 형식이 있으면와 TypeReference함께 사용해야합니다 convertValue().

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

또한 그것을 사용하여 pojo를 java.util.Map뒤로 변환 할 수 있습니다 .

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

2

Jackson과 BeanUtils를 모두 테스트했으며 BeanUtils가 훨씬 빠르다는 것을 알았습니다.
내 컴퓨터 (Windows8.1, JDK1.7) 에서이 결과를 얻었습니다.

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

5
차이점은 Jackson은 전체 유형 변환 프레임 워크를 가지고 있다는 것입니다. 예를 들어 Mapcontains map.put("data","2016-06-26")TestClassfield private LocalDate data;가 있으면 Jackson은 작업을 수행 할 수 있지만 BeanUtils는 실패합니다.
Benjamin M

6
ObjectMapper인스턴스 생성 은 시간 / 자원 소비 프로세스 라고 들었는데 매번 새로 생성하는 대신 매퍼 인스턴스 하나를 재사용하는 것이 좋습니다. 나는 테스트 lop에서 그것을 꺼내는 것이 좋을 것이라고 생각한다
Mixaz

3
BeanUtils는 첫 번째 반복 후에 캐시 할 수 있지만 ObjectMapper에는 기회가 없으므로 공정한 테스트는 아닙니다.
Lucas Ross

1

지금까지 Jackson을 사용하여 제공된 답변은 훌륭하지만 여전히 다음과 같이 다른 s 를 변환 하는 데 도움 이되는 util 기능을 사용할 수 있습니다 .POJO

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

0

Map을 POJO로 변환 예제. Map 키에 밑줄이 있고 필드 변수가 hump입니다.

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

App.class 테스트 예제

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)
 */

0

@Hamedz 많은 데이터를 사용하는 경우, 가벼운 데이터를 변환하기 위해 Jackson을 사용하고, 아파치를 사용하십시오 ... 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; } }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.