XDoclet - check annotation from other class - java

I'm using XDoclet to generate code:
/**
* #diff.special
*/
public String myString;
Now I'd like to generate code depending on this annotation AND an annotation in an other class, i.e.
if annotation in class 1 = diff.special
===> decide what to do according to annotation in class 2
if annotation in class 1 = diff.normal
===> decide what to do according to annotation in class 3
How can I achieve that in my handler? When my ant task runs and is working on annotation in class 1, how can I get the annotations of class 2 or 3?
Thanks a LOT,
Haemi

Don't know if it's the best way to do, but I solved it the following way:
final XJavaDoc xJavaDoc = XDocletTagSupport.getXJavaDoc();
final XClass xClass = xJavaDoc.getXClass(clazz.getCanonicalName());
// iterate over all fields in the angebot class and...
for (Object field : xClass.getFields(true)) {
final XField xfield = (XField) field;
// ... check if it contains the corresponding field, ...
if (xfield.getName().contains(fieldNameToLookFor)) {
return xfield;
}
}

Related

Spring Boot merge configuration properties

I've a use case where I need to bind configuration properties based on two prefixes, one of which is determined at runtime. Let's say the constant prefix is foo and the runtime prefix is bar.
Given a new instance of Java Bean class FooBar, the code should bind all environment variables FOO_, then overwrite with all environment variables BAR_.
There's a way to dynamically bind a prefix to a class, as I had stated in this ticket (sample code shown below). However, what's missing is the merging of the results.
var bindable = Bindable.of(FooBar.class);
var properties = ConfigurationPropertySources.get(env);
new Binder(properties)
.bind("prefix", bindable)
.orElse(new FooBar());
Example:
public class FooBar {
private Duration latency = Duration.ofMillis(500L);
// other properties
// getters, setters
}
If there are no environment variables FOO_LATENCY or BAR_LATENCY, FooBar.getLatency() is 500 ms. If only one of FOO_LATENCY and BAR_LATENCY is present, FooBar.getLatency() takes its value. If both FOO_LATENCY and BAR_LATENCY are present, FooBar.getLatency() takes the value of BAR_LATENCY.
Any idea how can this be done?
UPDATED
Just call bind again. It only assigns values that are found in the configuration properties, and last prefix bound will win, on a property-by-property basis.
Example
class FooBar {
private String a;
private String b = "B";
private String c;
private String d;
private String e = "E";
// Getter, setters, and toString here
}
Properties (YAML)
x.a: Hello
x.b: World
z.a: Goodbye
z.c: Test
Test
Binder binder = Binder.get(env);
FooBar fooBar = new FooBar();
System.out.println(fooBar);
fooBar = binder.bind("x", Bindable.ofInstance(fooBar)).orElse(fooBar);
System.out.println(fooBar);
fooBar = binder.bind("y", Bindable.ofInstance(fooBar)).orElse(fooBar);
System.out.println(fooBar);
fooBar = binder.bind("z", Bindable.ofInstance(fooBar)).orElse(fooBar);
System.out.println(fooBar);
Output
FooBar[a=null, b=B, c=null, d=null, e=E]
FooBar[a=Hello, b=World, c=null, d=null, e=E]
FooBar[a=Hello, b=World, c=null, d=null, e=E]
FooBar[a=Goodbye, b=World, c=Test, d=null, e=E]
As you can see, the third binding overrides the values from the first, but only for properties that are actually configured, which is why the second binding does nothing.
I also simplified the logic to skip the use of ConfigurationPropertySources.get().

How to create a single add method for different entities?

How can I create a single add method that will insert different entities in the jdbc? I want to use annotations and reflection for that.
I have created 2 annotations:
(...)
public #interface Column {
String name();
boolean isPrimaryKey() default false;
}
and
(...)
public #interface Table {
String name();
}
Suppose we have 2 entities/models/etc. : Client and Waiter. For both we should make 2 add methods, each with own INSERT.
If we have like 4 entities, we should have 4 add methods for each entity. Instead of having 4 add methods, how can I make just 1 add method? and by using the annotations and the reflection.
Eg:
#Table(name = "Table_Client")
public class Client{
#Column(name = "ID", isPrimaryKey = true)
private long id;
#Column(name = "FULL_NAME")
private String name;
}
#Table(name = "Table_Waiter")
public class Waiter {
#Column(name = "FULL_NAME", isPrimaryKey = true)
private String name;
#Column(name = "AGE")
private int age;
}
case: db.add(Client c1) => add to the database in the table Table_Client the client c1
db.add(Waiter w1) => add to the database in the table Table_Waiter the waiter w1
and so on...
My idea is to take the class of the given object and scan it for the TYPE annotation to get the table's name. Then, take all the field's annotations and make a dynamic INSERT INTO VALUES query, but the problem is that I can't actually do that, because I can't pass the object's arguments.
Another question: if this can be done, update and delete methods can follow the same path?
I cannot refrain from mentioning how many holes you may find in the road ahead. But judging from the comments, that's the path you want to explore.
First of all, regarding your existing code, you need to apply a retention meta-annotation to your annotations, Column and Table. For example:
#Retention(RetentionPolicy.RUNTIME)
public #interface Column {
String name();
boolean isPrimaryKey() default false;
}
This meta-annotation will ensure that you can read your annotations at runtime through reflection.
Then, you need to inspect the class searching for these annotations at both class and field levels.
The Class class will have everything you need. You should know you can get it from any object by calling the getClass method. It contains a couple of important methods for what you are trying to achieve:
getAnnotation(Class c) will return the annotation if it exists, or null otherwise.
getDeclaredFields will return all declared class fields, even private ones.
At a field level, the Field class provides the following methods:
getAnnotation(Class c), same as above, will return the annotation if it exists, or null otherwise.
getType will return the class associated with the field
Now consider the following piece of code:
public static void inspectClass(Class<?> cls) {
Table t = cls.getAnnotation(Table.class);
if (t != null) {
System.out.print(t.name() + " --> ");
for (Field f: cls.getDeclaredFields()) {
Column c = f.getAnnotation(Column.class);
if (c != null) {
System.out.print(c.name()
+ " "
+ f.getType().getSimpleName()
+ (c.isPrimaryKey() ? " PK" : "") + ", ");
}
}
}
}
Applying this to your Client class, for instance, would return something like:
Table_Client --> ID long PK, FULL_NAME String,
Of course, this needs some work, but the idea is there.
EDIT:
To access values of an instance through reflection at runtime, for creating a dynamic INSERT statement, that could be done by calling get method on the Field class. When dealing with private fields though, it's necessary to tweak the privacy mode first:
f.setAccessible(true);
Object value = f.get(myInstance);

Is there a way to get the declared value of constraint in hibernate validator in another class?

Using the hibernate validator i declare something like this
public class TestSomething{
#Length(max=30, message="Error Message.")
private String name;
getter and setter here
}
is it possible to get the maximum number of character in this case 30
something like
TestSomething ts = new TestSomething();
int maxValue = ts.getName.getThatMaximumNumberOrSomethng
will java reflection on this kind of situation?
You should use the Bean Validation metadata API. Provided you have a Validator instance you can get hold of a so called ConstraintDescriptor:
BeanDescriptor beanDescriptor = getBeanDescriptor( TestSomething.class );
PropertyDescriptor propertyDescriptor = beanDescriptor.getConstraintsForProperty( "name" );
Set<ConstraintDescriptor<?>> constraintDescriptors = propertyDescriptor.getConstraintDescriptors();
Once you have the right ConstraintDescriptor you can either call
constraintDescriptor.getAnnotation(); // to get the actual constraint annotation
constraintDescriptor.getAttributes().get("max"); // to retrieve the attribute from the attributes map provided by the descriptor as convenience

Multiple instances of generic class

I'm trying to create a generic DAO in order to avoid having more or less the same code in many separate DAOs.
My problem is that in the following lines of code:
private BaseDAOImpl<Artist> baseDAOArtist = new BaseDAOImpl<>(Artist.class);
private BaseDAOImpl<ArtistRelation> baseDAOArtistRelation = new BaseDAOImpl<>(ArtistRelation.class);
The first one seems to be skipped.
An excerpt of the BaseDAOImpl:
public class BaseDAOImpl<T> implements BaseDAO<T> {
private Class<T> entity;
private DAOFactory daoFactory = Config.getInstance().getDAOFactory();
private static String SQL_FIND_BY_ID;
public BaseDAOImpl(Class entity) {
this.entity = entity;
SQL_FIND_BY_ID = "SELECT * FROM VIEW_" + entity.getSimpleName() + " WHERE id = ?";
}
}
Is it not possible to instantiate multiple objects this way?
Yes. It's not clear what you mean by "The first one seems to be skipped." but it could be that your using a static value for "SQL_FIND_BY_ID"? As at the moment:
private BaseDAOImpl<Artist> baseDAOArtist = new BaseDAOImpl<>(Artist.class);
Creates two instance variables and sets the value of SQL_FIND_BY_ID then:
private BaseDAOImpl<ArtistRelation> baseDAOArtistRelation = new BaseDAOImpl<>(ArtistRelation.class);
Creates two new instance variables and will change the value "SQL_FIND_BY_ID" for both instances.
Without a more detailed description of the error I am more or less guessing now, but judging from variable names and the code snippet I would suspect the static field SQL_FIND_BY_ID to be the cause.
When you instantiate the two DAOs, the second execution of the constructor BaseDAOImpl will overwrite the value of the static field. If the DAO relies on the SQL query stored there, it will always query for the entity of the last instantiated DAO.
Static fields and methods are shared among all instances of a class even if they differ on their generic parameters. In contrast to e.g. C++'s templates, there are no separate classes generated for each generic parameter.
To achieve the desired behavior of separate queries for each entity you may change the static field to a non-static member.

Java annotations

I've created simple annotation in Java
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Column {
String columnName();
}
and class
public class Table {
#Column(columnName = "id")
private int colId;
#Column(columnName = "name")
private String colName;
private int noAnnotationHere;
public Table(int colId, String colName, int noAnnotationHere) {
this.colId = colId;
this.colName = colName;
this.noAnnotationHere = noAnnotationHere;
}
}
I need to iterate over all fields, that are annotated with Column and get name and value of field and annotation. But I've got problem with getting value of each field, since all of them are of different data type.
Is there anything that would return collection of fields that have certain annotation?
I managed to do it with this code, but I don't think that reflection is good way to solve it.
Table table = new Table(1, "test", 2);
for (Field field : table.getClass().getDeclaredFields()) {
Column col;
// check if field has annotation
if ((col = field.getAnnotation(Column.class)) != null) {
String log = "colname: " + col.columnName() + "\n";
log += "field name: " + field.getName() + "\n\n";
// here i don't know how to get value of field, since all get methods
// are type specific
System.out.println(log);
}
}
Do I have to wrap every field in object, which would implement method like getValue(), or is there some better way around this? Basicly all I need is string representation of each field that is annotated.
edit: yep field.get(table) works, but only for public fields, is there any way how to do this even for private fields? Or do I have to make getter and somehow invoke it?
Every object should has toString() defined. (And you can override this for each class to get a more meaningful representation).
So you where your "// here I don't know" comment is, you could have:
Object value = field.get(table);
// gets the value of this field for the instance 'table'
log += "value: " + value + "\n";
// implicitly uses toString for you
// or will put 'null' if the object is null
Reflection is exactly the way to solve it. Finding out things about types and their members at execution time is pretty much the definition of reflection! The way you've done it looks fine to me.
To find the value of the field, use field.get(table)
Reflection is exactly the way to look at annotations. They are a form of "metadata" attached to the class or method, and Java annotations were designed to be examined that way.
Reflection is one way to process the object (probably the only way if the fields are private and don't have any kind of accessor method). You'll need to look at Field.setAccessible and perhaps Field.getType.
Another approach is to generate another class for enumerating the annotated fields using a compile-time annotation processor. This requires a com.sun API in Java 5, but support is better in the Java 6 JDK (IDEs like Eclipse may require special project configuration).

Categories

Resources