JAVA object mapping library

Introduction

If the refilling work is performed manually for bean conversion, the amount of code will increase and maintainability is not good. There are useful methods like BeanUtils.copyProperties, but let's put together other mapping libraries.

FasterXML ObjectMapper https://github.com/FasterXML/jackson-databind

This is useful for JSON-related processing.

How to use

Added to build.gradle

build.gradle


// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8'

Bean class creation

package com.test.lombok;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class User {
	private String userId;
	
	private String userName;
	
	private String age;
	
	private String gender;
}

user.json sample creation

user.json


{
"userId": "user001",
"userName": "Test Taro",
"age": 20,
"gender": "famale"
}

Test code

package com.test.lombok;

import java.io.File;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;

public class TestMain {

	public static void main(String[] args) throws Exception {
		ObjectMapper mapper = new ObjectMapper();

		//Specified by file path
		User user1 = mapper.readValue(
				new File("C:\\workspace_sts\\lombok\\src\\main\\java\\com\\test\\lombok\\user.json"), User.class);
		System.out.println(user1);

		//Specify in URL format
		User user2 = mapper.readValue(TestMain.class.getResource("user.json"), User.class);
		System.out.println(user2);

		//Convert from string
		User user3 = mapper.readValue(
				"{\"userId\":\"user001\", \"userName\": \"Test Taro 2\", \"age\": 22, \"gender\": \"male\"}", User.class);
		System.out.println(user3);

		//Convert from object to string
		String jsonString = mapper.writeValueAsString(user3);
		System.out.println(jsonString);

		//Convert from string to Map
		Map<String, String> userMap = mapper.readValue(jsonString, Map.class);
		System.out.println(userMap);

	}

}

result:

User (userId = user001, userName = test Taro, age = 20, gender = famale) User (userId = user001, userName = test Taro, age = 20, gender = famale) User (userId = user001, userName = test Taro 2, age = 22, gender = male) {"userId": "user001", "userName": "Test Taro 2", "age": "22", "gender": "male"} {userId = user001, userName = test Taro 2, age = 22, gender = male}

ModelMapper http://modelmapper.org/

How to use

Added to build.gradle

build.gradle


	// https://mvnrepository.com/artifact/org.modelmapper/modelmapper
	compile group: 'org.modelmapper', name: 'modelmapper', version: '2.3.5'

Former Bean class

package com.test.lombok;

import lombok.Data;

@Data
public class User {
	private String userId;
	
	private String userName;
	
	private String age;
	
	private String gender;
	
	private Address addr;
}

@Data
class Address {
	private String zipCode;
	private String address1;
	private String address2;
	private String address3;
}

DTO class

package com.test.lombok;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class UserDTO {
	private String userId;

	private String userName;

	private String age;

	private String gender;
	
	private String addrZipCode;
	
	private String addrAddress1;
	
	private String addrAddress2;
	
	private String addrAddress3;
}

Test code

package com.test.lombok;

import org.modelmapper.ModelMapper;

public class TestMain {

	public static void main(String[] args) throws Exception {
		ModelMapper modelMapper = new ModelMapper();
		
		User user = new User();
		user.setUserId("user001");
		user.setUserName("test");
		user.setAge("18");
		user.setGender("male");
		Address addr = new Address();
		addr.setZipCode("984-0031");
		addr.setAddress1("○○ prefecture");
		user.setAddr(addr );
		
		UserDTO userDTO = modelMapper.map(user, UserDTO.class);
		System.out.println(userDTO);

	}

}

result:

UserDTO (userId = user001, userName = test, age = 18, gender = male, addrZipCode = 984-0031, addrAddress1 = ○○ prefecture, addrAddress2 = null, addrAddress3 = null)

Explicit Mapping

package com.test.lombok;

import org.modelmapper.ModelMapper;
import org.modelmapper.TypeMap;

public class TestMain {

	public static void main(String[] args) throws Exception {
		ModelMapper modelMapper = new ModelMapper();

		User user = new User();
		user.setUserId("user001");
		user.setUserName("test");
		user.setAge("18");
		user.setGender("male");
		Address addr = new Address();
		addr.setZipCode("984-0031");
		addr.setAddress1("○○ prefecture");
		user.setAddr(addr);

		TypeMap<User, UserDTO> typeMap = modelMapper.typeMap(User.class, UserDTO.class).addMappings(mapper -> {
			mapper.map(src -> src.getAddr().getZipCode(), UserDTO::setAddrZipCode);
			mapper.map(src -> src.getAddr().getAddress1(), UserDTO::setAddrAddress1);
		});

		System.out.println(typeMap.map(user));

	}

}

result:

UserDTO (userId = user001, userName = test, age = 18, gender = male, addrZipCode = 984-0031, addrAddress1 = ○○ prefecture, addrAddress2 = null, addrAddress3 = null)

It is convenient to use it to convert Form Bean to your own DTO with SpringBoot Controller.

MapStruct https://mapstruct.org/

How to use

Added to build.gradle

build.gradle


plugins {
    id 'java'
    id 'net.ltgt.apt' version '0.20'
}

repositories {
    jcenter()
}

dependencies {
    // lombok
    compileOnly "org.projectlombok:lombok:1.18.12"
    annotationProcessor "org.projectlombok:lombok:1.18.12"
    
	// https://mvnrepository.com/artifact/org.mapstruct/mapstruct
	implementation  group: 'org.mapstruct', name: 'mapstruct', version: '1.3.1.Final'
	
	// https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor
	annotationProcessor group: 'org.mapstruct', name: 'mapstruct-processor', version: '1.3.1.Final'
    
}

[compileJava, compileTestJava]*.options*.encoding= "UTF-8"

sourceSets {
    main.java.srcDirs += "build/generated/sources/annotationProcessor/java/main"
}

Mapper interface

package com.test.lombok;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface UserMapper {
	UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

	@Mapping(source = "addr.zipCode", target = "addrZipCode")
	@Mapping(source = "addr.address1", target = "addrAddress1")
	@Mapping(source = "addr.address2", target = "addrAddress2")
	UserDTO userToUserDTO(User user);
}

After defining and building above, the UserMapperImpl.java class will be generated in build \ generated \ sources \ annotationProcessor \ java \ main \ com \ test \ lombok.

UserMapperImpl.java


package com.test.lombok;

import javax.annotation.Generated;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2020-06-28T21:47:47+0900",
    comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_201 (Oracle Corporation)"
)
public class UserMapperImpl implements UserMapper {

    @Override
    public UserDTO userToUserDTO(User user) {
        if ( user == null ) {
            return null;
        }

        UserDTO userDTO = new UserDTO();

        userDTO.setAddrAddress2( userAddrAddress2( user ) );
        userDTO.setAddrAddress1( userAddrAddress1( user ) );
        userDTO.setAddrZipCode( userAddrZipCode( user ) );
        userDTO.setUserId( user.getUserId() );
        userDTO.setUserName( user.getUserName() );
        userDTO.setAge( user.getAge() );
        userDTO.setGender( user.getGender() );

        return userDTO;
    }

    private String userAddrAddress2(User user) {
        if ( user == null ) {
            return null;
        }
        Address addr = user.getAddr();
        if ( addr == null ) {
            return null;
        }
        String address2 = addr.getAddress2();
        if ( address2 == null ) {
            return null;
        }
        return address2;
    }

    private String userAddrAddress1(User user) {
        if ( user == null ) {
            return null;
        }
        Address addr = user.getAddr();
        if ( addr == null ) {
            return null;
        }
        String address1 = addr.getAddress1();
        if ( address1 == null ) {
            return null;
        }
        return address1;
    }

    private String userAddrZipCode(User user) {
        if ( user == null ) {
            return null;
        }
        Address addr = user.getAddr();
        if ( addr == null ) {
            return null;
        }
        String zipCode = addr.getZipCode();
        if ( zipCode == null ) {
            return null;
        }
        return zipCode;
    }
}

Test code

package com.test.lombok;

public class TestMain {

	public static void main(String[] args) throws Exception {

		User user = new User();
		user.setUserId("user001");
		user.setUserName("test");
		user.setAge("18");
		user.setGender("male");
		Address addr = new Address();
		addr.setZipCode("984-0031");
		addr.setAddress1("○○ prefecture");
		user.setAddr(addr);


		UserDTO userDTO = UserMapper.INSTANCE.userToUserDTO(user);

		System.out.println(userDTO);

	}
}

result:

UserDTO (userId = user001, userName = test, age = 18, gender = male, addrZipCode = 984-0031, addrAddress1 = ○○ prefecture, addrAddress2 = null, addrAddress3 = null)

ClassNotFound error

Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.test.lombok.TestMain.main(TestMain.java:18)
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: Cannot find implementation for com.test.lombok.UserMapper
	at org.mapstruct.factory.Mappers.getMapper(Mappers.java:61)
	at com.test.lombok.UserMapper.<clinit>(UserMapper.java:9)
	... 1 more
Caused by: java.lang.ClassNotFoundException: Cannot find implementation for com.test.lombok.UserMapper
	at org.mapstruct.factory.Mappers.getMapper(Mappers.java:75)
	at org.mapstruct.factory.Mappers.getMapper(Mappers.java:58)

Add sourceSets to build.gradle

build.gradle


sourceSets {
    main.java.srcDirs += "build/generated/sources/annotationProcessor/java/main"
}

Details Doc: https://mapstruct.org/documentation/stable/reference/html/

Dozer https://github.com/DozerMapper/dozer

How to use

Added to build.gradle

build.gradle


// https://mvnrepository.com/artifact/com.github.dozermapper/dozer-core
compile group: 'com.github.dozermapper', name: 'dozer-core', version: '6.5.0'

Test code

package com.test.lombok;

import org.modelmapper.ModelMapper;
import org.modelmapper.TypeMap;

import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;

public class TestMain {

	public static void main(String[] args) throws Exception {

		User user = new User();
		user.setUserId("user001");
		user.setUserName("test");
		user.setAge("18");
		user.setGender("male");
		Address addr = new Address();
		addr.setZipCode("984-0031");
		addr.setAddress1("○○ prefecture");
		user.setAddr(addr);

		Mapper mapper = DozerBeanMapperBuilder.buildDefault();
		UserDTO userDTO = mapper.map(user, UserDTO.class);

		System.out.println(userDTO);

	}
}

result:

UserDTO (userId = user001, userName = test, age = 18, gender = male, addrZipCode = null, addrAddress1 = null, addrAddress2 = null, addrAddress3 = null)

The same item name was copied, but otherwise null.

In case of different items, it can be defined by XML, API and annotation.

If the item name is different, it can be handled by setting like @Mapping ("binaryData") , but if it is a complicated type, it must be set in XML.

I think you can choose your favorite library.

that's all

Recommended Posts

JAVA object mapping library
[Java] Object class
Java coverage measurement library
Java object size feeling
Java bidirectional map library
Java CSV library "opencsv"
Java tree structure library
Use fast Mapping library MapStruct with Lombok and Java 11
Java Object Serialization why & when
[Design pattern] Java core library
Muscle Java Object Oriented Day 1
Muscle Java Object Oriented Day 2 ~ Inheritance ~
Bean mapping useful in Java ModelMapper
[Effective Java] Remove obsolete object references
Java
Java cache library and Eviction Policy
Welcome to the Java Library Swamp! !!
Java
Call Java library from C with JNI
I tried Cassandra's Object Mapper for Java
Points when mapping Value Object in MyBatis
Java Artery-Easy to use unit test library
[Beginner] Java method / class / external library [Note 23]
Mapping json to an already instantiated Object
[Java] Use cryptography in the standard library
2018 Java Recommended library for easily creating microservices
[Java] Convert Object type null to String type
Immutable (immutable) List object conversion function in Java8
[Java] Let's make a DB access library!
Flexible data type conversion mechanism of O / R mapping library Lightsleep for Java 8