Annotation Processor
Annotation processors can be used to generate the classes at compile time basis on specified annotations. So we can define annotations, we can use them on classes and then we can process them using annotation processor.Here we will see how we can use Annotation processor in Java to generate the classes at runtime. We will try to generate the DTO (Data transfer object) classes from entity classes. There are situation when a developer has to write DTO classes for the Entity class with almost same fields, so data can be transferred from one layer to another layer like UI to backend and backend to UI. We can use entity objects also to transfer between UI and backed but it will create more problem instead of solving as entity objects live in transaction context and reading or updating them in non-transactional context may change their state which may not be as expected. I just took the example of UI and backend but there can be many other scenario when it is required to transfer the data using DTO classes to hide the backend object or revealing only required data instead of whole business object data.
It becomes like a repeated task to create two similar classes, one for entity and another for DTO. How it will be if we just create entity class and tell the compiler to generate the similar DTO class from it? Yes, we can achieve it using the annotation processor in java. Now we will see the implementation.
We will create two different applications as given below.
1. DTO Generator
This application will have the custom annotations which will be used to annotate the entity classes and then annotation processors will generate the DTO class.Custom Annotations
com.ttj.dtogen.annotations.DtoClassThis annotation will be used on Entity classes and has below attributes.
- name - Class name for DTO class to be generated, if not given then annotated class name will be used as DTO class name by adding "Dto" to end of the name.
- classPackage - Package where DTO class need to be generated, if not given then annotated class's package will be use by adding "dto" as sub-package under it.
- includeAllFields - If true then all the fields will be used for DTO generation otherwise only those fields will be use which have DtoProperty annotation.
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) /** * This annotation is used to mark the class which * will be read by annotation processor to generate the DTO classes */ public @interface DtoClass { /** * Class name, if not given then annotated class name will be used * by appending Dto to it. * @return */ String name() default ""; /** * Package where DTO class need to be generated, if not given * then annotated class's package will be use by adding "dto" * subpackage under it. * @return */ String classPackage() default ""; /** * if true then all the fields will be used for DTO generation * @return */ boolean includeAllFields() default false; }com.ttj.dtogen.annotations.DtoProperty
This annotation is used to annotate the field of entity class which we want to include in DTO class. Below are the attributes available with this annotation.
- name - New name for the field, if not given then annotated field's name will be used.
- getter - If true then getter method will be generated.
- setter - If true then setter method will be generated.
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) /** * This annotation is used to annotate the fields in entity classes * which we want to include in DTO class */ public @interface DtoProperty { /** * new name for the field, if not given then annotated * field's name will be used * @return */ String name() default ""; /** * if true then getter method will be created * @return */ boolean getter() default true; /** * if true then setter method will be generated * @return */ boolean setter() default true; }
Annotation Processor
Below is the class implemented as annotation processor.com.ttj.dtogen.processors.DTOAnnotationProcessor
This class will read all the classes which are annotated with the "DtoClass" annotation at compile time and generate the DTO classes.
This class need to extend the "AbstractProcessor" class and override below methods.
- public synchronized void init(ProcessingEnvironment processingEnv) - This method is used to initialize the environment related variables which will be required during the annotation processing.
- public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) - This is the main method where we need to keep our logic to process the classes with DtoClass annotation and generate the DTO classes as per specified configurations.
- public Set<String> getSupportedAnnotationTypes() - This method returns the list of annotations which are supported by this processor, for example - DtoClass.
- public SourceVersion getSupportedSourceVersion() - This method return the supported version.
public class DTOAnnotationProcessor extends AbstractProcessor{ private Types typeUtils; private Elements elementUtils; private Filer filer; private Messager messager; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); typeUtils = processingEnv.getTypeUtils(); elementUtils = processingEnv.getElementUtils(); filer = processingEnv.getFiler(); messager = processingEnv.getMessager(); } private String getValue(String value, String defaultValue){ if(value==null || value.length()<1) return defaultValue; else return value; } private String[] getClassDetails(DtoClass classAnnotation, TypeElement classElem){ String[] classDetails = new String[2]; String parentQualifiedClassName = classElem.getQualifiedName().toString(); String parentClassName = classElem.getSimpleName().toString(); String parentPackage = parentQualifiedClassName.substring(0, parentQualifiedClassName.indexOf(parentClassName)); //set package details classDetails[0] = getValue(classAnnotation.classPackage(), (parentPackage==null?"":parentPackage)+"dto"); //set class name classDetails[1] = getValue(classAnnotation.name(), parentClassName+"Dto"); return classDetails; } @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) { for(Element element : roundEnv.getElementsAnnotatedWith(DtoClass.class)){ try { DtoClass classAnnotation = element.getAnnotation(DtoClass.class); String[] classDetails = getClassDetails(classAnnotation, (TypeElement)element); String qualifiedGenClass = classDetails[0]+"."+classDetails[1]; JavaFileObject javaFileObject = filer.createSourceFile(qualifiedGenClass); if(new File(javaFileObject.toUri()).exists()) { continue; } Writer writer = javaFileObject.openWriter(); JavaFileBuilder javaFileBuilder = new JavaFileBuilder(classDetails[1], classDetails[0]); //iterating through annotated fields for(Element fieldElem : element.getEnclosedElements()){ DtoProperty propAnnotation = fieldElem.getAnnotation(DtoProperty.class); String fieldName = null; String fieldType = null; boolean isGetter = true, isSetter = true; if(propAnnotation!=null) { fieldName = propAnnotation.name(); isGetter = propAnnotation.getter(); isSetter = propAnnotation.setter(); } if(propAnnotation!=null || classAnnotation.includeAllFields()) { if(fieldElem instanceof VariableElement) { if (fieldName == null || fieldName.length() < 1) { fieldName = fieldElem.getSimpleName().toString(); } VariableElement varElem = (VariableElement) fieldElem; fieldType = varElem.asType().toString(); messager.printMessage(Diagnostic.Kind.NOTE, MessageFormat.format("[Class: %s] Processing field[%s] for type[%s]", qualifiedGenClass, fieldName, fieldType)); javaFileBuilder.addField(fieldType, fieldName, isGetter, isSetter); } } } writer.write(javaFileBuilder.toClassCodeString()); writer.close(); }catch(Exception e){ e.printStackTrace(); messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage()); } } return true; } @Override public Set<String> getSupportedAnnotationTypes() { Set<String> annotationTypes = new HashSet<>(); annotationTypes.add(DtoClass.class.getCanonicalName()); return annotationTypes; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } }com.ttj.dtogen.utils.JavaFileBuilder
This class is an utility class which is used to generate the source code for target class. You can check the source code in GIT whose link is given in the below section.
META-INF/services/javax.annotation.processing.Processor
This file is required to register the annotation by putting the qualified processor class name separated by new line.
com.ttj.dtogen.processors.DTOAnnotationProcessor
Maven Settings
Below dependencies are required for annotations API.<dependencies> <!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api --> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency> </dependencies>Below plugin will be configured with the compiler configuration as "-proc:none" which is required to not to run the annotation processor in it's own build otherwise you will face compilation error. Please note that this setting is required only in source code build of annotation processor.
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <compilerArgument> -proc:none </compilerArgument> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>Below is the complete GIT source code of annotation processor application.
https://github.com/thetechnojournals/misc_codes/tree/master/DTOGenerator
2. DTO Gen Test
This application will use the DTO Generator application as dependency and annotate the Entity classes with provided annotations. DTO classes will be generated during the compilation of this application.Entity Class
Below are the two entity classes, for which we are going to generate the DTO classes at compile time.com.ttj.dtogen.DepartmentEntity
Below is the code of this class where we told at class annotation to include all the fields so we don't need to annotate all the fields. But if we do then that will take precedence over this.
@DtoClass(includeAllFields = true) public class DepartmentEntity { private String deptName; @DtoProperty(name="specialNumber", getter = false, setter = true) private Double splNumber; private Map<String, List<String>> empList; }com.ttj.dtogen.TestEntity
This class need to annotate all the fields to get them available in DTO class. See the below code.
@DtoClass(name="TestDto", classPackage = "com.ttj.dtogen.dto") public class TestEntity { private String testId; @DtoProperty private String name; @DtoProperty(name="age", getter=true, setter = true) private Integer age; @DtoProperty(name="address", getter=true, setter = false) private String address; }
Maven Settings
We need below dependency to use the annotations and annotation processor with our test application.<dependency> <groupId>com.ttj.dtogen</groupId> <artifactId>dto-generator</artifactId> <version>1.0-SNAPSHOT</version> </dependency>Below plugin is required if we need to generate the classes under specified source directory, otherwise you may see this generated code under target folder.
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> <generatedSourcesDirectory> ${project.basedir}/src/main/java </generatedSourcesDirectory> </configuration> </plugin> </plugins> </build>Below is the complete GIT source code for DTO Gen Test application.
https://github.com/thetechnojournals/misc_codes/tree/master/DTOGenTest
Executing the application
- Build the DTO Generator application.
- Build the DTO Gen Test application.
com.ttj.dtogen.dto.DepartmentEntityDto
package com.ttj.dtogen.dto; import java.util.List; import java.lang.Double; import java.util.Map; import java.lang.String; public class DepartmentEntityDto{ private String deptName; private Double specialNumber; private Map<String,List<String>> empList; public String getDeptName(){ return deptName; } public void setDeptName(String deptName){ this.deptName = deptName; } public void setSpecialNumber(Double specialNumber){ this.specialNumber = specialNumber; } public Map<String,List<String>> getEmpList(){ return empList; } public void setEmpList(Map<String,List<String>> empList){ this.empList = empList; } }com.ttj.dtogen.dto.TestDto
package com.ttj.dtogen.dto; import java.lang.String; import java.lang.Integer; public class TestDto{ private String name; private Integer age; private String address; public String getName(){ return name; } public void setName(String name){ this.name = name; } public Integer getAge(){ return age; } public void setAge(Integer age){ this.age = age; } public String getAddress(){ return address; } }
Please check below link in case you interested in how to populate DTO objects using entity object.
https://www.thetechnojournals.com/2019/10/entity-object-conversion-to-dto-object.html
instagram takipçi satın al
ReplyDeleteucuz takipçi
takipçi satın al
https://takipcikenti.com
https://ucsatinal.org
instagram takipçi satın al
https://perdemodelleri.org
https://yazanadam.com
instagram takipçi satın al
balon perdeler
petek üstü perde
mutfak tül modelleri
kısa perde modelleri
fon perde modelleri
tül perde modelleri
https://atakanmedya.com
https://fatihmedya.com
https://smmpaketleri.com
https://takipcialdim.com
https://yazanadam.com
yasaklı sitelere giriş
aşk kitapları
yabancı şarkılar
sigorta sorgula
https://cozumlec.com
word indir ücretsiz
tiktok jeton hilesi
rastgele görüntülü sohbet
fitness moves
gym workouts
https://marsbahiscasino.org
http://4mcafee.com
http://paydayloansonlineare.com
This comment has been removed by a blog administrator.
ReplyDeletemmorpg oyunları
ReplyDeleteinstagram takipçi satın al
Tiktok jeton hilesi
tiktok jeton hilesi
ANTALYA SAÇ EKİMİ
referans kimliÄŸi nedir
instagram takipçi satın al
metin2 pvp serverlar
Ä°NSTAGRAM TAKÄ°PCÄ° SATIN AL
perde modelleri
ReplyDeletesms onay
Vodafone Mobil Ödeme Bozdurma
NFTNASÄ°LALÄ°NÄ°R.COM
Ankara Evden Eve Nakliyat
trafik sigortası
dedektör
WEB SÄ°TESÄ° KURMA
Aşk Kitapları
ümraniye samsung klima servisi
ReplyDeletekartal mitsubishi klima servisi
tuzla arçelik klima servisi
çekmeköy samsung klima servisi
ataÅŸehir samsung klima servisi
çekmeköy mitsubishi klima servisi
ataÅŸehir mitsubishi klima servisi
kadıköy vestel klima servisi
maltepe bosch klima servisi
It s a very useful page. Thank you. 34a7b1f54c29dd6ee7916223fe4cfbe5
ReplyDeleteakseki
yesilyurt
yenisehir
havran
koprubasi
yenimahalle
germencik
atasehir
turgutlu
Congratulations on your article, it was very helpful and successful. 9652ca1e3406b8226eb7823983fc04c4
ReplyDeletenumara onay
website kurma
sms onay
Thank you for your explanation, very good content. 4ea57ff36a905639aec6a2740a171ac9
ReplyDeletealtın dedektörü
With most slots that includes a Return to Player of 92-96%, any games with a Return to Player above 96% is a good selection. In terms of win-size, progressive slots are the slot machines that pay one of the best – but they're also those with the bottom winning odds. Finding a great casino bonus is 솔카지노 essential to play slots on-line – especially if you want to|if you want to} get a small advantage. The most typical bonus varieties include free spins, more money that matches your deposit, and special provides for recurring gamers.
ReplyDeleteGood content. You write beautiful things.
ReplyDeletetaksi
hacklink
mrbahis
korsan taksi
sportsbet
mrbahis
vbet
sportsbet
vbet
Good text Write good content success. Thank you
ReplyDeletemobil ödeme bahis
tipobet
kibris bahis siteleri
betpark
kralbet
slot siteleri
poker siteleri
betmatik
elf bar
ReplyDeletebinance hesap açma
sms onay
UEBC
elazığ
ReplyDeletekağıthane
kastamonu
nevÅŸehir
niÄŸde
yalova
40W2
kıbrıs
ReplyDeletetrabzon
zonguldak
mersin
diyarbakır
8KQEN
salt likit
ReplyDeletesalt likit
5Ä°RGK
https://saglamproxy.com
ReplyDeletemetin2 proxy
proxy satın al
knight online proxy
mobil proxy satın al
HQDYAW
https://saglamproxy.com
ReplyDeletemetin2 proxy
proxy satın al
knight online proxy
mobil proxy satın al
LB54
https://saglamproxy.com
ReplyDeletemetin2 proxy
proxy satın al
knight online proxy
mobil proxy satın al
LTWV4
web postegro
ReplyDeletetakipcimx 1000
techy hit tools
0VG