ฉันดูที่แจ็คสัน แต่ดูเหมือนว่าฉันจะต้องแปลงแผนที่เป็น JSON และจากนั้นผลลัพธ์ JSON เป็น POJO
มีวิธีแปลงแผนที่โดยตรงเป็น POJO หรือไม่?
ฉันดูที่แจ็คสัน แต่ดูเหมือนว่าฉันจะต้องแปลงแผนที่เป็น JSON และจากนั้นผลลัพธ์ JSON เป็น POJO
มีวิธีแปลงแผนที่โดยตรงเป็น POJO หรือไม่?
คำตอบ:
คุณสามารถบรรลุเป้าหมายนั้นด้วยแจ็คสันด้วยเช่นกัน (และดูเหมือนว่าจะสะดวกสบายมากขึ้นตั้งแต่คุณกำลังพิจารณาใช้แจ็คสัน)
ใช้ObjectMapper
's convertValue
วิธีการ:
final ObjectMapper mapper = new ObjectMapper(); // jackson's objectmapper
final MyPojo pojo = mapper.convertValue(map, MyPojo.class);
ไม่จำเป็นต้องแปลงเป็นสตริง JSON หรืออย่างอื่น การแปลงโดยตรงทำได้เร็วกว่ามาก
Map<String, Object>
ตัวอย่าง?
วิธีแก้ปัญหาด้วยGson :
Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(map);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);
map.toString()
จะให้สตริงที่ถูกต้อง? การใช้งานของtoString()
ไม่รับประกันรูปแบบที่เฉพาะเจาะจง
ใช่เป็นไปได้แน่นอนที่จะหลีกเลี่ยงการแปลงระดับกลางเป็น 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, name = Bob, age = 23, saving = 2500.39]
หมายเหตุ: หากคุณเปลี่ยนซอร์สแผนที่เป็น a Map<String, Object>
คุณสามารถคัดลอกคุณสมบัติที่ซ้อนกันแบบลึก ๆ ได้ (โดยMap<String, String>
คุณจะได้รับเพียงหนึ่งระดับ)
ถ้าคุณมีประเภททั่วไปในชั้นเรียนของคุณคุณควรใช้กับTypeReference
convertValue()
final ObjectMapper mapper = new ObjectMapper();
final MyPojo<MyGenericType> pojo = mapper.convertValue(map, new TypeReference<MyPojo<MyGenericType>>() {});
นอกจากนี้คุณสามารถใช้มันเพื่อแปลง pojo เป็นjava.util.Map
back
final ObjectMapper mapper = new ObjectMapper();
final Map<String, Object> map = mapper.convertValue(pojo, new TypeReference<Map<String, Object>>() {});
ฉันได้ทำการทดสอบทั้ง 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));
}}
Map
บรรจุmap.put("data","2016-06-26")
และTestClass
มีฟิลด์private LocalDate data;
จากนั้นแจ็คสันก็สามารถทำสิ่งต่าง ๆ ได้ในขณะที่ BeanUtils จะล้มเหลว
ObjectMapper
อินสแตนซ์เป็นกระบวนการที่ใช้เวลา / ทรัพยากรและขอแนะนำให้ใช้อินสแตนซ์ mapper หนึ่งครั้งแทนที่จะสร้างใหม่ในแต่ละครั้ง ฉันคิดว่ามันจะเป็นการดีกว่าถ้าเอามันออกจากการทดสอบลพบุรี
คำตอบที่ให้ไว้เมื่อใช้แจ็คสันนั้นดีมาก แต่คุณก็ยังมีฟังก์ชั่น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;
}
แปลงแผนที่เป็นตัวอย่าง POJO แจ้งให้ทราบถึงคีย์แผนที่ประกอบด้วยขีดเส้นใต้และตัวแปรฟิลด์คือโคก
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)
*/
@Hamedz หากใช้ข้อมูลจำนวนมากให้ใช้ Jackson เพื่อแปลงข้อมูลแสงใช้ apache ... 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;
}
}
compile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'