Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
vadere
vadere
Commits
6a3b6451
Commit
6a3b6451
authored
May 15, 2018
by
Stefan Schuhbaeck
Browse files
Add source generation code and refactor existing annotation Processors.
parent
3e9fa287
Changes
22
Hide whitespace changes
Inline
Side-by-side
VadereAnnotation/src/org/vadere/annotation/factories/AbstractFactoryProcessor.java
0 → 100644
View file @
6a3b6451
package
org.vadere.annotation.factories
;
import
org.vadere.annotation.factories.dataprocessors.DataProcessorClass
;
import
org.vadere.annotation.factories.outputfiles.OutputFileClass
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
javax.annotation.processing.AbstractProcessor
;
import
javax.annotation.processing.RoundEnvironment
;
import
javax.lang.model.element.Element
;
import
javax.lang.model.element.ElementKind
;
import
javax.lang.model.element.Modifier
;
import
javax.lang.model.element.TypeElement
;
/**
* Base FactoryProcessor to generate Factories
*
* Factories are crated with two annotations: {@link FactoryType} and a specific Annotation Interface
* declaring a new Factory. {@link FactoryType} is used to annotate the specific annotation used
* for factories (i.e. {@link OutputFileClass}, {@link DataProcessorClass},
* {@link org.vadere.annotation.factories.models.ModelClass} and
* {@link org.vadere.annotation.factories.attributes.ModelAttributeClass})
*
* The {@link AbstractFactoryProcessor} defines process loop used to
* generate java source files. It also provides abstract methods as hooks to allow
* child classes to add additional elements into the generated java source file.
* All hooks have access to the PrintWriter used to create the java source file as well
* the Set of TypElements annotated with the specific annotation used in this {@link javax.annotation.processing.Processor}
*
* <ul>
* <li>{@link #addImports(Set, PrintWriter)}: </br>
* This hook allows the implementing class to add additional import statements
* which where not mentioned in the {@link FactoryType} annotation interface.
* </li>
* <li>{@link #addMembers(Set, PrintWriter)}: </br>
* This hook allows the implementing class to add additional members to the new
* java source file.
* </li>
* <li>{@link #addLastConstructor(Set, PrintWriter)}: </br>
* This hook allows the implementing class to add additional statement to the
* Constructor of the new Factory. Only the Default constructor is implemented!
* </li>
* <li>{@link #addLastConstructor(Set, PrintWriter)}: </br>
* This hook allows the implementing class to add additional function to the
* new java source file.
* </li>
* </ul>
*
*
* {@link #addImports(Set, PrintWriter)}
*/
public
abstract
class
AbstractFactoryProcessor
extends
AbstractProcessor
{
private
static
final
String
QUOTE
=
"\""
;
protected
String
factoryClassName
;
//Name of the new Factory
protected
String
extendedClassName
;
//Name of the Factory which needs to be extended.
protected
String
genericFactoryTypes
;
//Generics if extendedClass needs it.
protected
String
factoryPackage
;
//Where to place the new Factory.
protected
String
[]
factoryImports
;
//Imports needed by the new Factory.
/**
* This method is called from the java compiler directly*
*/
@Override
public
boolean
process
(
Set
<?
extends
TypeElement
>
annotations
,
RoundEnvironment
roundEnv
)
{
for
(
TypeElement
annotation
:
annotations
)
{
//only no abstract classes...
Set
<?
extends
Element
>
annotatedElements
=
roundEnv
.
getElementsAnnotatedWith
(
annotation
)
.
stream
()
.
filter
(
e
->
e
.
getKind
().
isClass
()
&&
!
e
.
getKind
().
equals
(
ElementKind
.
ENUM
)
&&
!
e
.
getModifiers
().
contains
(
Modifier
.
ABSTRACT
)
)
.
collect
(
Collectors
.
toSet
());
if
(
annotatedElements
.
isEmpty
())
continue
;
setup
(
annotation
);
try
{
writeFactory
(
annotatedElements
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
return
true
;
}
protected
abstract
void
addImports
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
);
protected
abstract
void
addMembers
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
);
protected
abstract
void
addLastConstructor
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
);
protected
abstract
void
addLast
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
);
protected
String
name
(
Element
e
)
{
return
e
.
getSimpleName
().
toString
();
}
/**
* This method is called for each SupportedAnnotationTypes from the {@link #process(Set, RoundEnvironment)}
* method. The current implementation only allows ONE SupportedAnnotationTypes because this
* method build the whole java source file.
*
* @param elements Elements annotated with one of the SupportedAnnotationTypes
*/
protected
abstract
void
writeFactory
(
Set
<?
extends
Element
>
elements
)
throws
IOException
;
/**
* Create class statement based on information provided by the {@link FactoryType} annotation
*
* @param elements Elements annotated with one of the SupportedAnnotationTypes
* @param writer PrintWriter used to create the source file.
*/
protected
void
buildClass
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
)
{
writer
.
append
(
"public class "
).
append
(
factoryClassName
);
if
(!
extendedClassName
.
isEmpty
())
{
writer
.
append
(
" extends "
).
append
(
extendedClassName
);
if
(!
genericFactoryTypes
.
isEmpty
())
{
writer
.
append
(
"<"
).
append
(
genericFactoryTypes
).
append
(
"> "
);
}
}
writer
.
println
(
"{"
);
}
/**
* Create a getter for each Element in elements set. The underling TypeElement
* is a Class and must have a constructor without parameters.
*
* @param elements Elements annotated with one of the SupportedAnnotationTypes
* @param writer PrintWriter used to create the source file.
*/
protected
void
buildGetters
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
)
{
for
(
Element
element
:
elements
)
{
TypeElement
p
=
(
TypeElement
)
element
;
writer
.
append
(
" public "
).
append
(
p
.
getSimpleName
())
.
append
(
" get"
).
append
(
p
.
getSimpleName
()).
append
(
"()"
).
println
(
"{"
);
writer
.
append
(
" return new "
).
append
(
p
.
getSimpleName
()).
println
(
"();"
);
writer
.
append
(
" }"
).
println
();
writer
.
println
();
}
}
/**
* Creates a static method to provide a thread safe singletone implementation.
*/
protected
void
createSingletone
(
final
String
instanceType
,
PrintWriter
writer
){
writer
.
append
(
" private static "
).
append
(
instanceType
).
append
(
" instance;"
).
println
();
writer
.
println
();
writer
.
println
(
" //performance threadsafe Singletone. Sync block will only be used once"
);
writer
.
append
(
" public static "
).
append
(
instanceType
).
append
(
" instance(){"
).
println
();
writer
.
println
(
" if(instance == null){"
);
writer
.
append
(
" synchronized ("
).
append
(
instanceType
).
append
(
".class){"
).
println
();
writer
.
println
(
" if(instance == null){"
);
writer
.
append
(
" instance = new "
).
append
(
instanceType
).
append
(
"();"
).
println
();
writer
.
println
(
" }"
);
writer
.
println
(
" }"
);
writer
.
println
(
" }"
);
writer
.
println
(
" return instance;"
);
writer
.
println
(
" }"
);
writer
.
println
();
}
protected
String
quote
(
final
String
data
){
return
QUOTE
+
data
+
QUOTE
;
}
private
void
setup
(
TypeElement
annotation
)
{
FactoryType
factoryType
=
annotation
.
getAnnotation
(
FactoryType
.
class
);
assert
factoryType
!=
null
;
this
.
factoryClassName
=
factoryType
.
factoryClassName
();
this
.
extendedClassName
=
factoryType
.
extendedClassName
();
this
.
genericFactoryTypes
=
factoryType
.
genericFactoryTypes
();
this
.
factoryPackage
=
factoryType
.
factoryPackage
();
this
.
factoryImports
=
factoryType
.
factoryImports
();
}
}
VadereAnnotation/src/org/vadere/annotation/factories/BaseFactoryProcessor.java
View file @
6a3b6451
...
...
@@ -4,144 +4,65 @@ package org.vadere.annotation.factories;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
javax.annotation.processing.AbstractProcessor
;
import
javax.annotation.processing.RoundEnvironment
;
import
javax.lang.model.element.Element
;
import
javax.lang.model.element.ElementKind
;
import
javax.lang.model.element.Modifier
;
import
javax.lang.model.element.TypeElement
;
import
javax.tools.JavaFileObject
;
public
abstract
class
BaseFactoryProcessor
extends
AbstractProcessor
{
protected
String
factoryType
;
protected
String
factoryClassName
;
protected
String
factoryPackage
;
protected
String
[]
factoryImports
;
protected
String
baseClass
;
public
BaseFactoryProcessor
(){
baseClass
=
"BaseFactory"
;
}
/**
* Implements the default layout of the java source file.
*/
public
abstract
class
BaseFactoryProcessor
extends
AbstractFactoryProcessor
{
@Override
public
boolean
process
(
Set
<?
extends
TypeElement
>
annotations
,
RoundEnvironment
roundEnv
)
{
for
(
TypeElement
annotation
:
annotations
){
//only no abstract classes...
Set
<?
extends
Element
>
annotatedElements
=
roundEnv
.
getElementsAnnotatedWith
(
annotation
)
.
stream
()
.
filter
(
e
->
e
.
getKind
().
isClass
()
&&
!
e
.
getKind
().
equals
(
ElementKind
.
ENUM
)
&&
!
e
.
getModifiers
().
contains
(
Modifier
.
ABSTRACT
)
)
.
collect
(
Collectors
.
toSet
());
if
(
annotatedElements
.
isEmpty
())
continue
;
FactoryType
factoryType
=
annotation
.
getAnnotation
(
FactoryType
.
class
);
assert
factoryType
!=
null
;
this
.
factoryType
=
factoryType
.
factoryType
();
this
.
factoryClassName
=
factoryType
.
factoryName
();
this
.
factoryPackage
=
factoryType
.
factoryPackage
();
this
.
factoryImports
=
factoryType
.
factoryImports
();
try
{
writeFactory
(
annotatedElements
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
return
true
;
}
protected
abstract
String
label
(
Element
element
);
protected
abstract
String
descr
(
Element
element
);
protected
String
name
(
Element
e
){
return
e
.
getSimpleName
().
toString
();
}
protected
abstract
void
addImports
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
);
protected
abstract
void
addLast
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
);
protected
abstract
void
addMembers
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
);
protected
abstract
void
addLastConstructor
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
);
private
void
writeFactory
(
Set
<?
extends
Element
>
elements
)
throws
IOException
{
protected
void
writeFactory
(
Set
<?
extends
Element
>
elements
)
throws
IOException
{
JavaFileObject
jFile
=
processingEnv
.
getFiler
().
createSourceFile
(
factoryClassName
);
try
(
PrintWriter
out
=
new
PrintWriter
(
jFile
.
openWriter
()))
{
out
.
append
(
"package "
).
append
(
factoryPackage
).
append
(
";"
).
println
();
out
.
println
();
out
.
println
(
"import org.vadere.util.factory.BaseFactory;"
);
// Add Imports start
for
(
String
factoryImport
:
factoryImports
)
{
out
.
append
(
"import "
).
append
(
factoryImport
).
println
(
";"
);
}
out
.
println
();
for
(
Element
e
:
elements
){
TypeElement
p
=
(
TypeElement
)
e
;
for
(
Element
e
:
elements
)
{
TypeElement
p
=
(
TypeElement
)
e
;
out
.
append
(
"import "
).
append
(
p
.
getQualifiedName
()).
println
(
";"
);
}
out
.
println
();
//add additional import defined by subclass
addImports
(
elements
,
out
);
//Add Import ends
out
.
println
();
out
.
println
();
out
.
append
(
"public class "
).
append
(
factoryClassName
).
append
(
" extends "
).
append
(
baseClass
).
append
(
"<"
).
append
(
factoryType
).
append
(
"> {"
).
println
();
// out.append("public class ").append(factoryClassName).append(" extends BaseFactory<").append(factoryType).append("> {").println();
buildClass
(
elements
,
out
);
out
.
println
();
addMembers
(
elements
,
out
);
out
.
println
();
Util
.
createSingletone
(
factoryClassName
,
out
);
createSingletone
(
factoryClassName
,
out
);
out
.
println
();
// private constructor.
out
.
append
(
" private "
).
append
(
factoryClassName
).
append
(
"(){"
).
println
();
out
.
println
(
" // add Members to Factory"
);
for
(
Element
e
:
elements
)
{
out
.
append
(
" addMember("
);
out
.
append
(
e
.
getSimpleName
().
toString
()).
append
(
".class, "
);
out
.
append
(
"this::"
).
append
(
"get"
).
append
(
name
(
e
)).
append
(
", "
);
out
.
append
(
Util
.
quote
(
label
(
e
))).
append
(
", "
);
out
.
append
(
Util
.
quote
(
descr
(
e
))).
append
(
");"
);
out
.
println
();
}
out
.
println
();
addLastConstructor
(
elements
,
out
);
out
.
println
(
" }"
);
out
.
println
();
out
.
println
();
out
.
println
();
out
.
println
(
" // Getters"
);
for
(
Element
element
:
elements
)
{
TypeElement
p
=
(
TypeElement
)
element
;
out
.
append
(
" public "
).
append
(
p
.
getSimpleName
())
.
append
(
" get"
).
append
(
p
.
getSimpleName
()).
append
(
"()"
).
println
(
"{"
);
out
.
append
(
" return new "
).
append
(
p
.
getSimpleName
()).
println
(
"();"
);
out
.
append
(
" }"
).
println
();
out
.
println
();
}
buildGetters
(
elements
,
out
);
out
.
println
(
"// additional methods"
);
//add additional methods defined by subclass
addLast
(
elements
,
out
);
out
.
println
();
out
.
println
(
"}"
);
}
}
...
...
VadereAnnotation/src/org/vadere/annotation/factories/FactoryType.java
View file @
6a3b6451
...
...
@@ -3,10 +3,34 @@ package org.vadere.annotation.factories;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Target
;
/**
* This annotation interface is used to annotate specific factory annotations. The members in this
* annotation provides information about the new factory java source file.
*/
@Target
(
ElementType
.
ANNOTATION_TYPE
)
public
@interface
FactoryType
{
String
factoryType
();
String
[]
factoryImports
();
String
factoryName
();
/**
* @return Nam of the new Factory class. This is mandatory.
*/
String
factoryClassName
();
/**
* @return Name of the super class if one exists.
*/
String
extendedClassName
()
default
""
;
/**
* @return Generic information for super class if one exists.
*/
String
genericFactoryTypes
()
default
""
;
/**
* @return List of imports needed for the new Factory class.
*/
String
[]
factoryImports
()
default
{};
/**
* @return Package name of the new Factory class. This is mandatory.
*/
String
factoryPackage
();
}
VadereAnnotation/src/org/vadere/annotation/factories/Util.java
deleted
100644 → 0
View file @
3e9fa287
package
org.vadere.annotation.factories
;
import
java.io.PrintWriter
;
public
class
Util
{
private
static
final
String
QUOTE
=
"\""
;
public
static
void
createSingletone
(
final
String
instanceType
,
PrintWriter
writer
){
writer
.
append
(
" private static "
).
append
(
instanceType
).
append
(
" instance;"
).
println
();
writer
.
println
();
writer
.
println
(
" //performance threadsafe Singletone. Sync block will only be used once"
);
writer
.
append
(
" public static "
).
append
(
instanceType
).
append
(
" instance(){"
).
println
();
writer
.
println
(
" if(instance == null){"
);
writer
.
append
(
" synchronized ("
).
append
(
instanceType
).
append
(
".class){"
).
println
();
writer
.
println
(
" if(instance == null){"
);
writer
.
append
(
" instance = new "
).
append
(
instanceType
).
append
(
"();"
).
println
();
writer
.
println
(
" }"
);
writer
.
println
(
" }"
);
writer
.
println
(
" }"
);
writer
.
println
(
" return instance;"
);
writer
.
println
(
" }"
);
writer
.
println
();
}
public
static
String
quote
(
final
String
data
){
return
QUOTE
+
data
+
QUOTE
;
}
}
VadereAnnotation/src/org/vadere/annotation/factories/attributes/BaseAttributeFactoryProcessor.java
0 → 100644
View file @
6a3b6451
package
org.vadere.annotation.factories.attributes
;
import
com.google.auto.service.AutoService
;
import
org.vadere.annotation.factories.BaseFactoryProcessor
;
import
java.io.PrintWriter
;
import
java.util.Set
;
import
javax.annotation.processing.Processor
;
import
javax.annotation.processing.SupportedAnnotationTypes
;
import
javax.annotation.processing.SupportedSourceVersion
;
import
javax.lang.model.SourceVersion
;
import
javax.lang.model.element.Element
;
import
javax.lang.model.element.TypeElement
;
@SupportedAnnotationTypes
(
"org.vadere.annotation.factories.attributes.ModelAttributeClass"
)
@SupportedSourceVersion
(
SourceVersion
.
RELEASE_8
)
@AutoService
(
Processor
.
class
)
public
class
BaseAttributeFactoryProcessor
extends
BaseFactoryProcessor
{
@Override
protected
void
addImports
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
)
{
}
@Override
protected
void
addMembers
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
)
{
}
@Override
protected
void
addLastConstructor
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
)
{
for
(
Element
e
:
elements
)
{
TypeElement
te
=
(
TypeElement
)
e
;
String
className
=
te
.
getSimpleName
().
toString
();
writer
.
append
(
" addMember("
);
writer
.
append
(
className
).
append
(
".class, "
);
writer
.
append
(
"this::"
).
append
(
"get"
).
append
(
name
(
e
)).
println
(
");"
);
}
}
@Override
protected
void
addLast
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
)
{
}
}
VadereAnnotation/src/org/vadere/annotation/factories/attributes/ModelAttributeClass.java
0 → 100644
View file @
6a3b6451
package
org.vadere.annotation.factories.attributes
;
import
org.vadere.annotation.factories.FactoryType
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Target
;
/**
* This annotation interface defines the ModelAttributeFactory. The main logic of the factory
* resides in the AttributeBaseFactory (util-Module). The generated java source file only
* provides the tedious getter and Map creations.
*/
@Target
(
ElementType
.
TYPE
)
@FactoryType
(
factoryClassName
=
"ModelAttributeFactory"
,
extendedClassName
=
"AttributeBaseFactory"
,
genericFactoryTypes
=
"Attributes"
,
factoryImports
=
{
"org.vadere.state.attributes.Attributes"
,
"org.vadere.util.factory.attributes.AttributeBaseFactory"
},
factoryPackage
=
"org.vadere.state.attributes"
)
public
@interface
ModelAttributeClass
{
}
VadereAnnotation/src/org/vadere/annotation/factories/DataProcessorClass.java
→
VadereAnnotation/src/org/vadere/annotation/factories/
dataprocessors/
DataProcessorClass.java
View file @
6a3b6451
package
org.vadere.annotation.factories
;
package
org.vadere.annotation.factories.dataprocessors
;
import
org.vadere.annotation.factories.FactoryType
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Target
;
/**
* This annotation interface defines the DataProcessorFactory. The main logic of the factory
* resides in the ProcessorBaseFactory (util-Module). The generated java source file only
* provides the tedious getter and Map creations.
*/
@Target
(
ElementType
.
TYPE
)
@FactoryType
(
factoryType
=
"DataProcessor<?, ?>"
,
factoryClassName
=
"DataProcessorFactory"
,
extendedClassName
=
"ProcessorBaseFactory"
,
genericFactoryTypes
=
"DataProcessor<?, ?>"
,
factoryImports
=
{
"org.vadere.simulator.projects.dataprocessing.processor.DataProcessor"
"org.vadere.simulator.projects.dataprocessing.processor.DataProcessor"
,
"org.vadere.util.factory.processors.ProcessorBaseFactory"
},
factoryName
=
"DataProcessorFactory"
,
factoryPackage
=
"org.vadere.simulator.projects.dataprocessing.processor"
)
public
@interface
DataProcessorClass
{
String
label
()
default
""
;
String
description
()
default
""
;
}
VadereAnnotation/src/org/vadere/annotation/factories/DataProcessorFactoryProcessor.java
→
VadereAnnotation/src/org/vadere/annotation/factories/
dataprocessors/
DataProcessorFactoryProcessor.java
View file @
6a3b6451
package
org.vadere.annotation.factories
;
package
org.vadere.annotation.factories
.dataprocessors
;
import
com.google.auto.service.AutoService
;
import
org.vadere.annotation.factories.BaseFactoryProcessor
;
import
java.io.PrintWriter
;
import
java.util.Set
;
...
...
@@ -11,23 +13,11 @@ import javax.annotation.processing.SupportedSourceVersion;
import
javax.lang.model.SourceVersion
;
import
javax.lang.model.element.Element
;
@SupportedAnnotationTypes
(
"org.vadere.annotation.factories.DataProcessorClass"
)
@SupportedAnnotationTypes
(
"org.vadere.annotation.factories.
dataprocessors.
DataProcessorClass"
)
@SupportedSourceVersion
(
SourceVersion
.
RELEASE_8
)
@AutoService
(
Processor
.
class
)
public
class
DataProcessorFactoryProcessor
extends
BaseFactoryProcessor
{
protected
String
label
(
Element
element
){
DataProcessorClass
dataProcessorClass
=
element
.
getAnnotation
(
DataProcessorClass
.
class
);
String
label
=
dataProcessorClass
.
label
();
return
label
.
isEmpty
()
?
element
.
getSimpleName
().
toString
()
:
label
;
}
protected
String
descr
(
Element
element
){
DataProcessorClass
dataProcessorClass
=
element
.
getAnnotation
(
DataProcessorClass
.
class
);
return
dataProcessorClass
.
description
();
}
@Override
protected
void
addImports
(
Set
<?
extends
Element
>
elements
,
PrintWriter
writer
)
{
writer
.
println
(
"import org.vadere.simulator.projects.dataprocessing.store.DataProcessorStore;"
);
...
...
@@ -40,13 +30,18 @@ public class DataProcessorFactoryProcessor extends BaseFactoryProcessor {
@Override