加入依赖:
<dependency><groupId>ma.glasnost.orika</groupId><artifactId>orika-core</artifactId><version>x.y.z</version>
</dependency>
/*** 测试属性复制功能:* - [x] 同名属性* - [x] 非同名属性* - [x] 导航属性,List,Map也可导航list[0],map['a']* - [x] List & Array* - [x] 集合泛型* - [x] 递归* - [x] 类型转换* - [x] 排除* ===========================================================* 同类型属性复制使用 CopyByReferenceConverter* 当同名属性不同类型,又没使用converter,或converter无效,会报错* ===========================================================* * 注意不要使用 MapperFacade.mapList ,应该使用foreach: BoundMapperFacade.map* * 性能差10倍+,在复制10_000_000个对象的情况下*/
public class OrikaTest {private MapperFactory mapperFactory;private ObjectMapper objectMapper;static final Gson gson = new GsonBuilder().disableHtmlEscaping().enableComplexMapKeySerialization().setPrettyPrinting().setDateFormat("yyyy-MM-dd HH:mm:ss Z").serializeNulls().create();@Beforepublic void setup() {objectMapper = new ObjectMapper();mapperFactory = new DefaultMapperFactory.Builder().build();/* 注册类型转换器(全局)*/// mapperFactory.getConverterFactory().registerConverter(new LocalDatetimeConverter());/* 注册类型转换器(非全局) */mapperFactory.getConverterFactory().registerConverter("LocalDateTime2Long", new LocalDateTime2LongConverter());/* 注册<PollutantSource.class,PollutantSourceDTO> 属性复制配置 */// PollutantSource -> PollutantSourceDTOmapperFactory.classMap(PollutantSource.class, PollutantSourceDTO.class).field("socialCode", "orgCode") //非同名属性.field("longitude", "geo.longitude") //导航属性.field("latitude", "geo.latitude") //导航属性.fieldMap("gmtCreated", "gmtCreated").converter("LocalDateTime2Long") // 这个属性使用 converter.add().byDefault().register();/* 递归 */mapperFactory.classMap(Xzqh.class, Xzqh2.class)// Xzqh -> Xzqh2.field("name", "name2").field("code", "code2").byDefault().register();}@Testpublic void testOrika() throws JsonProcessingException {/* 通用的 MapperFacade ,屏蔽对mapperFactory 底层接口 */// MapperFacade mapperFacade = mapperFactory.getMapperFacade();/* 专用的 BoundMapperFacade<<PollutantSource, PollutantSourceDTO>> ,屏蔽对mapperFactory 底层接口*/BoundMapperFacade<PollutantSource, PollutantSourceDTO> mapperFacade = mapperFactory.getMapperFacade(PollutantSource.class, PollutantSourceDTO.class);PollutantSource ps = new PollutantSource();ps.addresses = Lists.newArrayList("贵州省贵阳市花果园", "贵州省贵安新区马场镇", "贵州省遵义市");ps.gmtCreated = LocalDateTime.now();ps.id = "123123";ps.latitude = "24.24";ps.longitude = "110.10";ps.socialCode = "520510500";ps.xzqhs = Lists.newArrayList(new Xzqh("5201", "贵州省贵阳市"), new Xzqh("5203", "贵州省遵义市"), new Xzqh("529001", "贵州省贵安新区"));/* map */PollutantSourceDTO psDTO = mapperFacade.map(ps);System.out.println(objectMapper.writeValueAsString(psDTO));System.out.println(gson.toJson(psDTO));/* reverse map */PollutantSource ps2 = mapperFacade.mapReverse(psDTO);System.out.println(objectMapper.writeValueAsString(ps2));System.out.println(gson.toJson(ps2));}// 自定义单向 converter// class LocalDateTime2LongConverter extends CustomConverter<LocalDateTime, Long> {//// @Override// public Long convert(LocalDateTime localDateTime, Type<? extends Long> type) {// return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();// }// }// 自定义双向 converterclass LocalDateTime2LongConverter extends BidirectionalConverter<LocalDateTime, Long> {@Overridepublic Long convertTo(LocalDateTime localDateTime, Type<Long> destinationType, MappingContext mappingContext) {return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();}@Overridepublic LocalDateTime convertFrom(Long source, Type<LocalDateTime> destinationType, MappingContext mappingContext) {return LocalDateTime.ofInstant(Instant.ofEpochMilli(source), ZoneOffset.of("+8").normalized());}}@Testpublic void benchmarkOrika() {long num = 10_000_000;ArrayList<Person> personList = Lists.newArrayList();ArrayList<Car> cars = Lists.newArrayList(new Car("bmw", new BigDecimal("150.34"), false),new Car("honda", new BigDecimal("77.88"), true));StopWatch sw = new StopWatch("2");sw.start("new objects");for (int i = 0; i < num; i++) {Person p = new Person();p.setAge(i);p.setName("person" + i);p.setCars(cars);personList.add(p);}sw.stop();mapperFactory.classMap(Person.class, People.class).exclude("cars").byDefault().register();// mapperFactory.classMap(Car.class, SUV.class).byDefault().register();BoundMapperFacade<Person, People> mapperFacade = mapperFactory.getMapperFacade(Person.class, People.class);Runtime rt = Runtime.getRuntime();long l = rt.freeMemory();sw.start("测试Orika map(" + num + ")");List<People> peopleList = personList.stream().map(mapperFacade::map).collect(Collectors.toList());sw.stop();System.out.println(sw.prettyPrint());System.out.println("memory-usage=" + ((l - rt.freeMemory()) / 1024) + "K");System.out.println(peopleList.get(11).getCars());// ObjectMapper om = new ObjectMapper();// System.out.println("person: " + om.writeValueAsString(personList.get(personList.size() - 11)));// System.out.println("person cars: " + personList.get(personList.size() - 11).getCars());// System.out.println("people: " + om.writeValueAsString(peopleList.get(peopleList.size() - 11)));// System.out.println("people cars: " + peopleList.get(peopleList.size() - 11).getCars());// SUV suv = peopleList.get(0).getCars().get(0);// System.out.println(suv);/*** 复制cars* StopWatch '2': running time (millis) = 188517* -----------------------------------------* ms % Task name* -----------------------------------------* 07349 004% new objects* 181168 096% 测试Orika mapAsList(10000000)*//*** 排除cars* memory-usage=512000K* StopWatch '2': running time (millis) = 101239* -----------------------------------------* ms % Task name* -----------------------------------------* 07108 007% new objects* 94131 093% 测试Orika mapAsList(10000000)*//*** 排除cars* memory-usage=593920K* -----------------------------------------* ms % Task name* -----------------------------------------* 06336 036% new objects* 11050 064% 测试Orika map(10000000)*/}@Testpublic void benchmarkBeanUtils() {long num = 10_000_000;ArrayList<Person> personList = Lists.newArrayList();ArrayList<Car> cars = Lists.newArrayList(new Car("bmw", new BigDecimal("150.34"), false),new Car("honda", new BigDecimal("77.88"), true));StopWatch sw = new StopWatch("2");sw.start("new objects");for (int i = 0; i < num; i++) {Person p = new Person();p.setAge(i);p.setName("person" + i);p.setCars(cars);personList.add(p);}sw.stop();mapperFactory.classMap(Person.class, People.class).exclude("cars").byDefault().register();// mapperFactory.classMap(Car.class, SUV.class).byDefault().register();BoundMapperFacade<Person, People> mapperFacade = mapperFactory.getMapperFacade(Person.class, People.class);Runtime rt = Runtime.getRuntime();long l = rt.freeMemory();sw.start("测试Orika map(" + num + ")");List<People> peopleList = personList.stream().map(person -> {People people = new People();try {BeanUtils.copyProperties(people, person);} catch (Exception e) {e.printStackTrace();}return people;}).collect(Collectors.toList());sw.stop();System.out.println(sw.prettyPrint());System.out.println("memory-usage=" + ((l - rt.freeMemory()) / 1024) + "K");System.out.println(peopleList.get(11).getCars());// ObjectMapper om = new ObjectMapper();// System.out.println("person: " + om.writeValueAsString(personList.get(personList.size() - 11)));// System.out.println("person cars: " + personList.get(personList.size() - 11).getCars());// System.out.println("people: " + om.writeValueAsString(peopleList.get(peopleList.size() - 11)));// System.out.println("people cars: " + peopleList.get(peopleList.size() - 11).getCars());// SUV suv = peopleList.get(0).getCars().get(0);// System.out.println(suv);/*** 复制cars* StopWatch '2': running time (millis) = 188517* -----------------------------------------* ms % Task name* -----------------------------------------* 07349 004% new objects* 181168 096% 测试Orika mapAsList(10000000)*//*** 排除cars* memory-usage=512000K* StopWatch '2': running time (millis) = 101239* -----------------------------------------* ms % Task name* -----------------------------------------* 07108 007% new objects* 94131 093% 测试Orika mapAsList(10000000)*//*** 排除cars* memory-usage=593920K* -----------------------------------------* ms % Task name* -----------------------------------------* 06336 036% new objects* 11050 064% 测试Orika map(10000000)*/}//==================================================================================// Entity & DTO//==================================================================================@Getter@Setterstatic class PollutantSource {private String id;private List<Xzqh> xzqhs; //递归测试,集合泛型测试private String socialCode; //非同名测试private LocalDateTime gmtCreated; //类型转换private List<String> addresses; //List & Array/* 导航属性 */private String latitude;private String longitude;}@Getter@Setterstatic class PollutantSourceDTO {private String id;private List<Xzqh2> xzqhs; //递归测试,集合泛型测试private String orgCode; //非同名测试private Long gmtCreated; //类型转换private String[] addresses; //List & Arrayprivate Geo geo;}@Getter@Setterstatic class Geo {private String latitude;private String longitude;}@Setter@Getter@AllArgsConstructor@NoArgsConstructorstatic class Xzqh {private String code;private String name;}@Setter@Getter@AllArgsConstructor@NoArgsConstructorstatic class Xzqh2 {private String code2;private String name2;}@Datastatic class Person {private int age;private String name;private List<Car> cars;}@Data@AllArgsConstructorstatic class Car {private String brand;private BigDecimal money;private boolean sellOut;}@Datastatic class People {private List<Car> cars;}//==================================================================// more advance example//==================================================================/*mapperFactory.classMap(Source.class, Destination.class).byDefault().customize(new CustomMapper<Source, Destination> {public void mapAtoB(A a, B b, MappingContext context) {// add your custom mapping code here}}.register();*//*mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class).mapNulls(false).mapNullsInReverse(false).fieldMap("field1", "fieldOne").mapNulls(true).mapNullsInReverse(true).add().field("field2", "fieldTwo").byDefault().register();*/
}