introduce

I recently changed my job and wrote this Java property mapping tool for about two full weeks.

When writing, I refer to some existing mapping tools such as Mapstruct, Dozer, Orika, BeanUtils, PropertyUtils, BeanCopier, etc., and write this attribute mapping tool from the perspective of performance, function, convenience, etc. The following is the introduction of today’s protagonists: Moon – mapper.

Next, I will introduce this tool from the perspective of usage and principle. We welcome all kinds of violent tests in Maven repository. We also hope that you can make it more powerful after using it.

I. Introduction to use

Making: github.com/moonsky-all…

Gitee: gitee.com/moonsky-all…

1. Install
<dependency>
  <groupId>io.github.moonsky-all</groupId>
  <artifactId>moon-mapper</artifactId>
  <version>0.1</version>
</dependency>
Copy the code
2. Basic usage

2.1. To register the mapper, you only need to add a annotation MapperFor on one of the classes to specify the class to be mapped to define the mapping relationship between the two classes;

BeanMapper = mapper2. get(Class, Class).

2.3. Use mapper.doForward(obj1, obj2)

public class UserEntity {

    private String username;
    
    private LocalDateTime birthday;
    
    // Omit other fields, getters, setters
}

// Add this annotation to define a mapping between two classes
// Here is the Class array, you can define multiple mappings
@MapperFor({UserEntity.class})
public class UserDO {

    // Get the mapper
    ThisPrimary is a simple method that can only be used in classes with MapperFor annotations
    // It gets the mapper between this class and the first class defined in MapperFor
    private static final BeanMapper MAPPER = Mapper2.thisPrimary();

    private String username;
    
    // This annotation is used for formatting. It can be used to format (parse) dates and numbers
    // Non-date/number/string relationships are ignored
    @MappingFormat("yyyy-MM-dd HH:mm:ss")
    private String birthday;
    
    // Omit other fields, getters, setters
}

public class Main {
    
    // mapper2. get(Class, Class) this is the normal way to get a mapper
    private static final BeanMapper MAPPER = Mapper2.get(UserDO.class, UserEntity.class);
    
    public static void main(String[] args) {
        UserDO userDo = new UserDO();
        
        // Mapper also has other methods, which can map forward or backward
        UserEntity entity = MAPPER.doForward(userDo, newUserEntity()); }}Copy the code
3. Automatic implicit type conversion

Mapper supports automatic type conversion between common data types:

  • Basic data types:byte,short,int,long,float,double,char,boolean;
  • Basic data type Wrapper class:Byte,Short,Integer,Long,Float,Double,Character,Boolean;
  • BigDecimal,BigInteger;
  • Date type:java.util.Date,util.Calendar,sql.Date,sql.Time,sql.Timestamp,java.time.XxxXxx,joda.time.XxxXxxSuch as the advicejoda-time 2.x+】;
  • Conversion between enumerations and strings and numbers;
  • Formatting and parsing strings between dates/numbers and strings;
Based on 4.setterOverloaded custom converter

The default data type automatic conversion functions mentioned above, but in some cases is certainly can’t satisfy the usage scenarios, so also provides the overloaded based on setter custom converter, because the Java language features, different parameters with the same type of method can be overloaded, as for the field to provide a different data type of the setter method, This is equivalent to providing a data converter of the specified type, such as:

public enum GenderEnum {
    MALE("Male"),
    FEMALE("Female");
    
    public final String text;
    
    GenderEnum(String text) { this.text = text; }}public class MemberEntity {

    private GenderEnum gender;
    
    // Omit other fields, getters, setters
    
    // Adding a gender setter of String is a custom converter
    public void setGender(String text) {
        if ("Male".equals(text)) {
            this.gender = GenderEnum.MALE;
        } else if ("Female".equals(text)) {
            this.gender = GenderEnum.FEMALE; }}}Copy the code

Custom converters are relatively easy to use and take full advantage of IDE code prompts and Java language features. It is one of the original intentions of Moon-Mapper to write code in strings as little as possible. I’ll talk about that later.)

5. SupportSpringThe environment

If the application is in Spring, you can use automatic injection if the application’s data class is in Spring scan scope, such as:

@Service
public class BusinessService {

    // Spring automatic injection
    @Autowired
    private BeanMapper<UserDO, UserEntity> userMapper;
}
Copy the code

Overall use down or relatively simple, add annotations MapperFor registration, and then use Mapper2 to obtain the mapper can be used, the next to explain the implementation principle.

Two, the implementation principle

Mapper2 is a statically compiled mapper, similar to mapstruct, which generates the same code as handwritten GET /set, so performance is guaranteed.

Registering a MapperFor generates two copiers representing the forward and reverse properties, and a Mapper Mapper encapsulates the first two Copiers. In Spring, the @Component annotation is added for automatic injection.

Tip: Remember Build -> Rebuild Project(in IDEA) every time you need to recompile; MVN clean compile also performs this process

Property replication is based on getter and setter methods, so the properties involved in the replication must have setter/getter methods with public modifications. At the same time, the data type of each property will be statically analyzed in the process of mapping. The same property of the same type can be directly bidirectional mapped. If it is a different data types, prefer using overloaded based on setter custom converter, and then analyze whether can use some default conversion, conversion between such as digital, Date, and long conversion between, Date/digital format, if can transform according to the conversion rule mapping, otherwise just ignore different types and different with the same name attribute mapping.

Three, description,

  1. supportjoda-timeDate library, but best used2.xThe above version,2.xAlthough the following version has also made part of the targeted treatment, but not perfect;
  2. So now the total is dividedmapperandprocessingTwo bags, one of whichprocessingIt’s best not to use any of the contents in the bag, the bag will be stripped out in the future;
  3. Mapping between attributes of different names is not currently provided separately, but can be done by adding the same namesetterTo achieve the same effect, at present this is the first version, will be improved;
  4. At present is the first version, only to achieve the most basic functions, I hope you can give more suggestions and improvement plan!! !