рдПрдиреЛрдЯреЗрд╢рди рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЗрд╕рдХреА рдкрд╡рд┐рддреНрд░ рдЬрд╛рдирдХрд╛рд░реА рд╣рд░ рдХрд┐рд╕реА рдХреЗ рд▓рд┐рдП рд╕реБрд▓рдн рдирд╣реАрдВ рд╣реИред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЬрд╛рджреВ рд╣реИ: рдореИрдВрдиреЗ рд╡рд┐рдзрд┐ / рдХреНрд╖реЗрддреНрд░ / рд╡рд░реНрдЧ рдкрд░ рдПрдХ рдХреБрддреНрддреЗ рдХреЗ рд╕рд╛рде рдПрдХ рдЬрд╛рджреВ рдХрд░ рджрд┐рдпрд╛ - рдФрд░ рддрддреНрд╡ рдЕрдкрдиреЗ рдЧреБрдгреЛрдВ рдХреЛ рдмрджрд▓рдирд╛ рд╢реБрд░реВ рдХрд░ рджреЗрддрд╛ рд╣реИ рдФрд░ рдирдП рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИред

рдЖрдЬ рд╣рдо рд╕реНрдкреНрд░рд┐рдВрдЧ рдПрдиреЛрдЯреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдиреЛрдЯреЗрд╢рди рдХреЗ рдЬрд╛рджреВ рдХреЛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдЬрд╛рдиреЗрдВрдЧреЗ: рд╕реЗрдо рдлрд╝реАрд▓реНрдб рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рдирд╛ред
рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣, рд▓реЗрдЦ рдХреЗ рдЕрдВрдд рдореЗрдВ GitHub рдкрд░ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рдПрдХ рд▓рд┐рдВрдХ рд╣реИ, рдЬрд┐рд╕реЗ рдбрд╛рдЙрдирд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рджреЗрдЦреЗрдВ рдХрд┐ рд╕рдм рдХреБрдЫ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
рдкрд┐рдЫрд▓реЗ
рд▓реЗрдЦ рдореЗрдВ, рдореИрдВрдиреЗ рдореЙрдбрд▓рдореИрдкрд░ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛, рдЬреЛ рдЖрдкрдХреЛ рдПрдХ рдЗрдХрд╛рдИ рдФрд░ рдбреАрдЯреАрдУ рдХреЛ рдПрдХ рджреВрд╕рд░реЗ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рд╣рдо рдЗрд╕ рдореИрдкрд░ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдкрд░ рдПрдиреЛрдЯреЗрд╢рди рдХреЗ рдХрд╛рдо рдореЗрдВ рдорд╣рд╛рд░рдд рд╣рд╛рд╕рд┐рд▓ рдХрд░реЗрдВрдЧреЗред
рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ, рд╣рдореЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рд╕рдВрд╕реНрдерд╛рдУрдВ рдФрд░ рдбреАрдЯреАрдУ рдХреЗ рдПрдХ рдЬреЛрдбрд╝реЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдореИрдВ рдЪреБрдирд┐рдВрджрд╛ рд░реВрдк рд╕реЗ рдПрдХ рдЬреЛрдбрд╝реА рджреВрдВрдЧрд╛ред
рдЧреНрд░рд╣@Entity @Table(name = "planets") @EqualsAndHashCode(callSuper = false) @Setter @AllArgsConstructor @NoArgsConstructor public class Planet extends AbstractEntity { private String name; private List<Continent> continents; @Column(name = "name") public String getName() { return name; } @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "planet") public List<Continent> getContinents() { return continents; } }
PlanetDto @EqualsAndHashCode(callSuper = true) @Data public class PlanetDto extends AbstractDto { private String name; private List<ContinentDto> continents; }
рдореИрдкрд░ред рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХреНрдпреЛрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдпрд╣ рдЗрд╕реА
рд▓реЗрдЦ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рд╣реИред
EntityDtoMapper public interface EntityDtoMapper<E extends AbstractEntity, D extends AbstractDto> { E toEntity(D dto); D toDto(E entity); }
AbstractMapper @Setter public abstract class AbstractMapper<E extends AbstractEntity, D extends AbstractDto> implements EntityDtoMapper<E, D> { @Autowired ModelMapper mapper; private Class<E> entityClass; private Class<D> dtoClass; AbstractMapper(Class<E> entityClass, Class<D> dtoClass) { this.entityClass = entityClass; this.dtoClass = dtoClass; } @PostConstruct public void init() { } @Override public E toEntity(D dto) { return Objects.isNull(dto) ? null : mapper.map(dto, entityClass); } @Override public D toDto(E entity) { return Objects.isNull(entity) ? null : mapper.map(entity, dtoClass); } Converter<E, D> toDtoConverter() { return context -> { E source = context.getSource(); D destination = context.getDestination(); mapSpecificFields(source, destination); return context.getDestination(); }; } Converter<D, E> toEntityConverter() { return context -> { D source = context.getSource(); E destination = context.getDestination(); mapSpecificFields(source, destination); return context.getDestination(); }; } void mapSpecificFields(E source, D destination) { } void mapSpecificFields(D source, E destination) { } }
PlanetMapper @Component public class PlanetMapper extends AbstractMapper<Planet, PlanetDto> { PlanetMapper() { super(Planet.class, PlanetDto.class); } }
рдлрд╝реАрд▓реНрдб рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рдиред
рдЕрдореВрд░реНрдд рдореИрдкрд░ рдХреНрд▓рд╛рд╕ рдореЗрдВ рдХреНрд▓рд╛рд╕ рдХреНрд▓рд╛рд╕ рдореЗрдВ рджреЛ рдлреАрд▓реНрдб рд╣реЛрддреЗ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдореЗрдВ рдЗрдореНрдкреНрд▓реАрдореЗрдВрдЯреЗрд╢рди рдореЗрдВ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рдирд╛ рд╣реЛрддрд╛ рд╣реИред
private Class<E> entityClass; private Class<D> dtoClass;
рдЕрдм рд╣рдо рдЗрд╕реЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрд░рддреЗ рд╣реИрдВред рд╕рдмрд╕реЗ рд╕реБрд░реБрдЪрд┐рдкреВрд░реНрдг рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ, рднрд▓реЗ рд╣реА рдЕрдкрдиреЗ рдЖрдк рдХреЛред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдореЗрд░рд╛ рд╕реБрдЭрд╛рд╡ рд╣реИ рдХрд┐ рдЖрдЧреЗ рдЪрд▓рдХрд░ рдПрдХ рдПрдиреЛрдЯреЗрд╢рди рд▓рд┐рдЦрд╛ рдЬрд╛рдП рдЬреЛ рдЗрди рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рдмрд┐рдирд╛ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЗ рд╕реЗрдЯ рдХрд░реЗрдЧрд╛ред
рд╢реБрд░реБрдЖрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдиреЛрдЯреЗрд╢рди рд╕реНрд╡рдпрдВ рд▓рд┐рдЦреЗрдВред рдХреЛрдИ рдЕрддрд┐рд░рд┐рдХреНрдд рдирд┐рд░реНрднрд░рддрд╛ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
рдореИрдЬрд┐рдХ рдбреЙрдЧ рдХреЛ рдХреНрд▓рд╛рд╕ рдХреЗ рд╕рд╛рдордиреЗ рдкреЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд▓рд┐рдЦреЗрдВрдЧреЗ:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented public @interface Mapper { Class<?> entity(); Class<?> dto(); }
@ рд░рд┐рдЯреЗрдВрд╢рди (RetentionPolicy.RUNTIME) - рдиреАрддрд┐ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╕рдВрдХрд▓рди рдХрд░рддреЗ рд╕рдордп рдПрдиреЛрдЯреЗрд╢рди рдХрд╛ рдкрд╛рд▓рди рд╣реЛрдЧрд╛ред рдЙрдирдореЗрдВ рд╕реЗ рддреАрди рд╣реИрдВ:
рд╕реНрд░реЛрдд - рд╕рдВрдХрд▓рди рдХреЗ рджреМрд░рд╛рди рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдиреЛрдЯреЗрд╢рди рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рдирд╣реАрдВ рд░рдЦрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрд╣ рд╡рд┐рдХрд▓реНрдк рд╣рдореЗрдВ рд╢реЛрднрд╛ рдирд╣реАрдВ рджреЗрддрд╛ред
CLASS - рдПрдиреЛрдЯреЗрд╢рди рд╕рдВрдХрд▓рди рдкрд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрд╣ рд╡рд┐рдХрд▓реНрдк рд╣реИ
рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдиреАрддрд┐ред
рд╕рдВрдХрд▓рди - рд╕рдВрдХрд▓рди рдХреЗ рджреМрд░рд╛рди
рдиреЛрдЯрдмрдВрджреА рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрд╛ рдЬрд╛рдПрдЧрд╛, рд╡рд░реНрдЪреБрдЕрд▓ рдорд╢реАрди рдЙрдиреНрд╣реЗрдВ рдПрдиреЛрдЯреЗрд╢рди рдХреЗ рд░реВрдк рдореЗрдВ рджреЗрдЦрддреА рд░рд╣реЗрдЧреА, рдЕрд░реНрдерд╛рдд рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рджреМрд░рд╛рди рдЙрдиреНрд╣реЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкреБрдирд░рд╛рд╡рд░реНрддреА рдХрд╣рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдЪреВрдВрдХрд┐ рд╣рдо рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдиреЛрдЯреЗрд╢рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ, рдпрд╣ рд╡рд┐рдХрд▓реНрдк рд╣реИ рдЬреЛ рд╣рдореЗрдВ рд╕реВрдЯ рдХрд░рддрд╛ рд╣реИред ред
рд▓рдХреНрд╖реНрдп ({ElementType.TYPE}) - рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдПрдиреЛрдЯреЗрд╢рди рдХреЛ рдХрд┐рд╕ рдЖрдзрд╛рд░ рдкрд░ рд▓рдЯрдХрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдпрд╣ рдПрдХ рдХреНрд▓рд╛рд╕, рдореЗрдердб, рдлреАрд▓реНрдб, рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░, рд▓реЛрдХрд▓ рд╡реИрд░рд┐рдПрдмрд▓, рдкреИрд░рд╛рдореАрдЯрд░, рд╡рдЧреИрд░рд╣ - рд╕рд┐рд░реНрдл 10 рдСрдкреНрд╢рди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ,
TYPE рдХрд╛ рдорддрд▓рдм рдПрдХ рд╡рд░реНрдЧ (рдЗрдВрдЯрд░рдлрд╝реЗрд╕) рд╣реИред
рдПрдиреЛрдЯреЗрд╢рди рдореЗрдВ, рд╣рдо рдЦреЗрддреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдлрд╝реАрд▓реНрдб рдореЗрдВ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдорд╛рди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ "рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдлрд╝реАрд▓реНрдб", рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП), рдлрд┐рд░ рдЙрдиреНрд╣реЗрдВ рднрд░рдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдирд╣реАрдВ рд╣реИред рдпрджрд┐ рдХреЛрдИ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдорд╛рди рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рдлрд╝реАрд▓реНрдб рднрд░рдирд╛ рд╣реЛрдЧрд╛ред
рдЕрдм рдореИрдкрд░ рдХреЗ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдбрд╛рд▓рддреЗ рд╣реИрдВ рдФрд░ рдЦреЗрддреЛрдВ рдореЗрдВ рднрд░рддреЗ рд╣реИрдВред
@Component @Mapper(entity = Planet.class, dto = PlanetDto.class) public class PlanetMapper extends AbstractMapper<Planet, PlanetDto> {
рд╣рдордиреЗ рдмрддрд╛рдпрд╛ рдХрд┐ рд╣рдорд╛рд░реЗ рдореИрдкрд░ рдХрд╛ рд╕рд╛рд░ Planet.class рд╣реИ, рдФрд░ DTO PlanetDto.class рд╣реИред
рд╣рдорд╛рд░реЗ рдмреАрди рдореЗрдВ рдПрдиреЛрдЯреЗрд╢рди рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдмреАрдирдкреЛрд╕реНрдЯрдкреНрд░реЛрд╕реЗрд╕рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдЬреЛ рд▓реЛрдЧ рдЬрд╛рдирддреЗ рд╣реИрдВ, рдЙрдирдХреЗ рд▓рд┐рдП рдмреАрдирдкреЛрд╕реНрдЯрдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрдм рдкреНрд░рддреНрдпреЗрдХ рдмреАрди рдХреЛ рдЖрд░рдВрднреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рджреЛ рд╡рд┐рдзрд┐рдпрд╛рдБ рд╣реИрдВ:
postProcessBeforeInitialization () - рдмреАрди рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
postProcessAfterInitialization () - рдмреАрди рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬреЗрд╢рди рдХреЗ рдмрд╛рдж рдирд┐рд╖реНрдкрд╛рджрд┐рддред
рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдкреНрд░рд╕рд┐рджреНрдз рд╕реНрдкреНрд░рд┐рдВрдЧ-рд░рд┐рдкрд░ рдПрд╡реЗрдЧреА рдмреЛрд░рд┐рд╕реЛрд╡ рдХреЗ рд╡реАрдбрд┐рдпреЛ рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ: "рдПрд╡рдЧреЗрдиреА рдмреЛрд░рд┐рд╕реЛрд╡ - рд╕реНрдкреНрд░рд┐рдВрдЧ-рд░рд┐рдкрд░ред" рдореИрдВ рджреЗрдЦрдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред
рддреЛ рдпрд╣рд╛рдБ рд╣реИред рд╣рдорд╛рд░реЗ рдкрд╛рд╕
Mapper рдПрдиреЛрдЯреЗрд╢рди рдХреЗ рд╕рд╛рде рдПрдХ рдмреАрди рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдХреНрд▓рд╛рд╕ рдХреНрд▓рд╛рд╕ рдХреЗ рдХреНрд╖реЗрддреНрд░ рд╣реИрдВред рдЖрдк рдХрд┐рд╕реА рднреА рд╡рд░реНрдЧ рдХреЗ рдХрд┐рд╕реА рднреА рдлрд╝реАрд▓реНрдб рдХреЛ рдПрдиреЛрдЯреЗрд╢рди рдореЗрдВ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред рддрдм рд╣рдореЗрдВ рдпреЗ рдХреНрд╖реЗрддреНрд░ рдореВрд▓реНрдп рдорд┐рд▓рддреЗ рд╣реИрдВ рдФрд░ рдЙрдирдХреЗ рд╕рд╛рде рдХреБрдЫ рднреА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдо рдмреАрди рдлрд╝реАрд▓реНрдб рдХреЛ рдПрдиреЛрдЯреЗрд╢рди рдорд╛рди рдХреЗ рд╕рд╛рде рдЖрд░рдВрдн рдХрд░рддреЗ рд╣реИрдВред
рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ MapperAnnotationProcessor рдмрдирд╛рддреЗ рд╣реИрдВ (рд╕реНрдкреНрд░рд┐рдВрдЧ рдХреЗ рдирд┐рдпрдореЛрдВ рдХреЗ рдЕрдиреБрд╕рд╛рд░, рд╕рднреА рдПрдиреЛрдЯреЗрд╢рди рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЛ ... рдПрдиреЛрдЯреЗрд╢рдирдкреНрд░реЛрд╕реЗрд╕рд░ рдореЗрдВ рд╕рдорд╛рдкреНрдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП) рдФрд░ рдЗрд╕реЗ рдмреАрдирдкреЛрд╕реНрдЯрдкреНрд░реЛрд╕реЗрд╕рд░ рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓рд╛ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЙрди рджреЛ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
@Component public class MapperAnnotationProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(@Nullable Object bean, String beanName) { return Objects.nonNull(bean) ? init(bean) : null; } @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { return bean; } }
рдпрджрд┐ рдХреЛрдИ рдмрд┐рди рд╣реИ, рддреЛ рд╣рдо рдЗрд╕реЗ рдПрдиреЛрдЯреЗрд╢рди рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде рдЖрд░рдВрдн рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рдЗрд╕реЗ рдПрдХ рдЕрд▓рдЧ рддрд░реАрдХреЗ рд╕реЗ рдХрд░реЗрдВрдЧреЗред рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рддрд░реАрдХрд╛:
private Object init(Object bean) { Class<?> managedBeanClass = bean.getClass(); Mapper mapper = managedBeanClass.getAnnotation(Mapper.class); if (Objects.nonNull(mapper)) { ((AbstractMapper) bean).setEntityClass(mapper.entity()); ((AbstractMapper) bean).setDtoClass(mapper.dto()); } return bean; }
рдмрд┐рди рдЖрд░рдВрднреАрдХрд░рдг рдХреЗ рджреМрд░рд╛рди, рд╣рдо рдЙрдирдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЪрд▓рддреЗ рд╣реИрдВ рдФрд░ рдпрджрд┐ рд╣рдо рдмрд┐рди рдХреЗ рдКрдкрд░
рдореИрдкрд░ рдПрдиреЛрдЯреЗрд╢рди рдкрд╛рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдмрд┐рди рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рдПрдиреЛрдЯреЗрд╢рди рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде рдЖрд░рдВрдн рдХрд░рддреЗ рд╣реИрдВред
рдпрд╣ рд╡рд┐рдзрд┐ рд╕рд░рд▓ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рд╣реА рдирд╣реАрдВ рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рднреЗрджреНрдпрддрд╛ рд╣реИред рд╣рдо рдПрдХ рдмрд┐рди рдЯрд╛рдЗрдк рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрд╕ рдмрд┐рди рдХреЗ рдХреБрдЫ рдЬреНрдЮрд╛рди рдкрд░ рднрд░реЛрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВред рдФрд░ рдХреЛрдИ рднреА рдХреЛрдб рдЬрд┐рд╕рдореЗрдВ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдЕрдкрдиреЗ рдирд┐рд╖реНрдХрд░реНрд╖ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ рд╡рд╣ рдЦрд░рд╛рдм рдФрд░ рдХрдордЬреЛрд░ рд╣реИред рд╣рд╛рдВ, рдФрд░ рдЖрдЗрдбрд┐рдпрд╛ рдЕрдирд┐рдпрдВрддреНрд░рд┐рдд рдХреЙрд▓ рдкрд░ рд╢рдкрде рд▓реЗрддрд╛ рд╣реИред
рд╕рдм рдХреБрдЫ рд╕рд╣реА рдХрд░рдиреЗ рдХрд╛ рдХрд╛рдо рдореБрд╢реНрдХрд┐рд▓ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдВрднрд╡ рд╣реИред
рд╡рд╕рдВрдд рдореЗрдВ рдПрдХ рдорд╣рд╛рди рдкрд░рд╛рд╡рд░реНрддрдирд╢реАрд▓ рдШрдЯрдХ рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рд╕рдмрд╕реЗ рд╕реБрд░рдХреНрд╖рд┐рдд рддрд░реАрдХреЗ рд╕реЗ рдкреНрд░рддрд┐рдмрд┐рдВрдм рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдФрд░ рд╣рдо рдЗрд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХреНрд╖реЗрддреНрд░ рдХреА рдХрдХреНрд╖рд╛рдУрдВ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВрдЧреЗред
рд╣рдорд╛рд░реА init () рд╡рд┐рдзрд┐ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧреА:
private Object init(Object bean) { Class<?> managedBeanClass = bean.getClass(); Mapper mapper = managedBeanClass.getAnnotation(Mapper.class); if (Objects.nonNull(mapper)) { ReflectionUtils.doWithFields(managedBeanClass, field -> { assert field != null; String fieldName = field.getName(); if (!fieldName.equals("entityClass") && !fieldName.equals("dtoClass")) { return; } ReflectionUtils.makeAccessible(field); Class<?> targetClass = fieldName.equals("entityClass") ? mapper.entity() : mapper.dto(); Class<?> expectedClass = Stream.of(ResolvableType.forField(field).getGenerics()).findFirst() .orElseThrow(() -> new IllegalArgumentException("Unable to get generic type for " + fieldName)).resolve(); if (expectedClass != null && !expectedClass.isAssignableFrom(targetClass)) { throw new IllegalArgumentException(String.format("Unable to assign Class %s to expected Class %s", targetClass, expectedClass)); } field.set(bean, targetClass); }); } return bean; }
рдЬреИрд╕реЗ рд╣реА рд╣рдореЗрдВ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рдШрдЯрдХ рдХреЛ
рдореИрдкрд░ рдПрдиреЛрдЯреЗрд╢рди рдХреЗ рд╕рд╛рде рдЪрд┐рд╣реНрдирд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд╣рдо ReflectionUtils.doWithFields рдХрд╣рддреЗ рд╣реИрдВ, рдЬреЛ рдЙрди рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рд╕реЗрдЯ рдХрд░реЗрдЧрд╛ рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рд╕реБрд░реБрдЪрд┐рдкреВрд░реНрдг рддрд░реАрдХреЗ рд╕реЗ рдЬрд╝рд░реВрд░рдд рд╣реИред рд╣рдо рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдлрд╝реАрд▓реНрдб рдореМрдЬреВрдж рд╣реИ, рдЙрд╕рдХрд╛ рдирд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ рдФрд░ рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ рдпрд╣ рдирд╛рдо рд╡рд╣ рд╣реИ рдЬрд┐рд╕рдХреА рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
assert field != null; String fieldName = field.getName(); if (!fieldName.equals("entityClass") && !fieldName.equals("dtoClass")) { return; }
рд╣рдо рдлрд╝реАрд▓реНрдб рдЙрдкрд▓рдмреНрдз рдХрд░рд╛рддреЗ рд╣реИрдВ (рдпрд╣ рдирд┐рдЬреА рд╣реИ)
ReflectionUtils.makeAccessible(field);
рд╣рдо рдлрд╝реАрд▓реНрдб рдореЗрдВ рдорд╛рди рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред
Class<?> targetClass = fieldName.equals("entityClass") ? mapper.entity() : mapper.dto(); field.set(bean, targetClass);
рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рднрд╡рд┐рд╖реНрдп рдХреЗ рдХреЛрдб рдХреЛ рдореИрдкрд░ рдорд╛рдкрджрдВрдбреЛрдВ (рд╡реИрдХрд▓реНрдкрд┐рдХ) рдореЗрдВ рдЧрд▓рдд рдЗрдХрд╛рдИ рдпрд╛ рдбреАрдЯреАрдУ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдХреЗ рдЗрд╕реЗ рддреЛрдбрд╝рдиреЗ рдХреЗ рдкреНрд░рдпрд╛рд╕реЛрдВ рд╕реЗ рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдо рдЬрд╛рдВрдЪрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдо рдЬрд┐рд╕ рд╡рд░реНрдЧ рдореЗрдВ рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рд╣реЛрдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рд╡рд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╣реИред
Class<?> expectedClass = Stream.of(ResolvableType.forField(field).getGenerics()).findFirst() .orElseThrow(() -> new IllegalArgumentException("Unable to get generic type for " + fieldName)).resolve(); if (expectedClass != null && !expectedClass.isAssignableFrom(targetClass)) { throw new IllegalArgumentException(String.format("Unable to assign Class %s to expected Class: %s", targetClass, expectedClass)); }
рдпрд╣ рдЬреНрдЮрд╛рди рдЗрд╕ рдЬрд╛рджреВ рдХреЗ рд╕рд╛рде рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдХреБрдЫ рдкреНрд░рдХрд╛рд░ рдХреЗ рдПрдиреЛрдЯреЗрд╢рди рдФрд░ рдЖрд╢реНрдЪрд░реНрдпрдЪрдХрд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╕рд╣рдпреЛрдЧрд┐рдпреЛрдВ рдХреЛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред рд▓реЗрдХрд┐рди рд╕рд╛рд╡рдзрд╛рди рд░рд╣реЗрдВ - рдЗрд╕ рддрдереНрдп рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд░рд╣реЗрдВ рдХрд┐ рд╕рднреА рдЖрдкрдХреЗ рдХреМрд╢рд▓ рдХреА рд╕рд░рд╛рд╣рдирд╛ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ :)
Github рдкрд░ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдпрд╣рд╛рдБ рд╣реИ:
promoscow@annotations.gitрдмрд┐рди рдЖрд░рдВрднреАрдХрд░рдг рдЙрджрд╛рд╣рд░рдг рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ AspectJ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рднреА рд╢рд╛рдорд┐рд▓ рд╣реИред рдореИрдВ рд▓реЗрдЦ рдореЗрдВ рд╕реНрдкреНрд░рд┐рдВрдЧ AOP / AspectJ рдХрд╛ рд╡рд┐рд╡рд░рдг рднреА рд╢рд╛рдорд┐рд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдкрд╛рдпрд╛ рдХрд┐ рдЗрд╕ рд╡рд┐рд╖рдп рдкрд░ Habr├й рдХрд╛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ
рдЕрджреНрднреБрдд рд▓реЗрдЦ рд╣реИ , рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЗрд╕реЗ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ред рдареАрдХ рд╣реИ, рдореИрдВ рдХрд╛рдо рдХреЛрдб рдФрд░ рд▓рд┐рдЦрд┐рдд рдкрд░реАрдХреНрд╖рд╛ рдЫреЛрдбрд╝ рджреВрдВрдЧрд╛ - рд╢рд╛рдпрдж рдпрд╣ рдХрд┐рд╕реА рдХреЛ AspectJ рдХреЗ рдХрд╛рдо рдХреЛ рд╕рдордЭрдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ред