LLVM vmkit java annotation - java

I am a novice in Java. I want to annotate (with a string) different Java variables that can be translated into LLVM IR (and get them by using llvm.var.annotation or llvm.global.annotations). In the case of C/C++, I use:
__attribute__((annotate("RED"))) static int a;
So a is annotated with the value "RED". My question is, how do I make this in Java (using vmkit for LLVM) ? I think I have to use #, but I do not know what libs do I have to add to vmkit and also how annotations in Java work?
Thank you for your answer !

Look for annotation tutorial in this link
http://docs.oracle.com/javase/tutorial/java/annotations/
what you need to do is to define your annotation than make some sort of reflection.
this is the #Red annotation
package test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Red {
}
and this how to use it
public class AnyClass {
#Red
public int a = 5;
}
here is a simple test to get the annotated field
package test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
public class TestClass {
/**
* #param args
*/
public static void main(String[] args) {
AnyClass anyClass = new AnyClass();
Class clasz = anyClass.getClass();
Field [] fArray = clasz.getFields();
Annotation[] anArray = clasz.getAnnotations();
for(Field f : fArray) {
System.out.println("wink" + f.getAnnotations()[0].annotationType());
}
}
}

Related

AspectJ: Pointcut to declare and retrieve an annotation of a method's parameter

I have read the following valuable links:
Spring AOP pointcut for annotated argument
How to write an Aspect pointcut based on an annotated parameter
AspectJ pointcut expression match parameter annotations at any position
Consider this request for a setter method
public void setSomething(#ParameterLevel(name="abc") String something){
this.something = something;
}
I have the following and works fine:
#Pointcut("execution(* *.*(#somepackage.ParameterLevel (*)))")
void parameterLevel01() {}
Now I want retrieve the #ParameterLevel annotation through a method's parameter such as the following:
#Pointcut("execution(* *.*(#somepackage.ParameterLevel (*)))")
void parameterLevel01(ParameterLevel parameterLevel) {} <--To be used directly in the advice method
The purpose is use the Annotation directly how a parameter in the advice method
Something similar such as:
#within(classLevel) for #ClassLevel in:
#ClassLevel
public class SomeClass {
...
}
#annotation(methodLevel) for #MethodLevel in:
#MethodLevel
public void somethingToDo(){
...
}
How accomplish this goal. Is possible? I am working with AspectJ 1.9.6
No matter if you use .., #MyAnnotation (*), .. or just #MyAnnotation (*), which only removes the ambiguity of possibly multiple matches, there is no direct way to bind a method argument annotation to an advice argument, only the method argument itself. This has not changed in AspectJ. You would have seen it mentioned in the release notes otherwise, because it would be a new feature.
So you will have to use the method from my other two answers which you have already linked to in your question, i.e. iterating over parameter types and annotations manually.
Somewhat off-topic, there is a very old Bugzilla ticket #233718 which is about binding multiple matched (annotated) parameters, but not about binding their annotations. It came up in a recent discussion I had with AspectJ maintainer Andy Clement. But even if this was implemented one day, it would not solve your problem.
I think you can take it from here and adapt my solution from the linked questions to your needs. Feel free to let me know if you have any follow-up questions about that, but it should be pretty straightforward. You might be able to optimise because you know the exact parameter position (think array index), if you feel so inclined, i.e. you don't need to iterate over all parameters.
Update: Here is a little MCVE for you. It is based on this answer and has been simplified to assume the annotation is always on the first parameter and the first parameter only.
Please learn what an MCVE is and provide one by yourself next time because it is your job, not mine. This was your free shot.
Marker annotation + driver application:
package de.scrum_master.app;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
#Retention(RUNTIME)
public #interface ParameterLevel {
String name();
}
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
new Application().doSomething("foo");
}
public void doSomething(#ParameterLevel(name="abc") String string) {}
}
Aspect:
package de.scrum_master.aspect;
import java.lang.annotation.Annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.SoftException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import de.scrum_master.app.ParameterLevel;
#Aspect
public class ParameterLevelAspect {
#Before("execution(public * *(#de.scrum_master.app.ParameterLevel (*))) && args(string)")
public void beforeAdvice(JoinPoint thisJoinPoint, String string) {
System.out.println(thisJoinPoint + " -> " + string);
MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature();
String methodName = signature.getMethod().getName();
Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
Annotation[] annotations;
try {
annotations = thisJoinPoint.getTarget().getClass()
.getMethod(methodName, parameterTypes)
.getParameterAnnotations()[0];
} catch (NoSuchMethodException | SecurityException e) {
throw new SoftException(e);
}
ParameterLevel parameterLevel = null;
for (Annotation annotation : annotations) {
if (annotation.annotationType() == ParameterLevel.class) {
parameterLevel = (ParameterLevel) annotation;
break;
}
}
assert parameterLevel != null;
System.out.println(" " + parameterLevel + " -> " + parameterLevel.name());
}
}
Console log:
execution(void de.scrum_master.app.Application.doSomething(String)) -> foo
#de.scrum_master.app.ParameterLevel(name="abc") -> abc

Java - How to edit annotation fields at runtime?

I wrote this simple annotation:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface CSVColumn {
String name();
int order();
}
which I'm currently using to annotate some getter methods of a class.
I'm able to get the values of this annotation at runtime:
Class classType = objects[0].getClass();
Method[] methodsArray = classType.getDeclaredMethods();
List<Method> methods = Arrays.asList(methodsArray);
//FIlter annotated methods
methods = methods.stream().filter(method -> method.getAnnotation(CSVColumn.class) != null).collect(Collectors.toList());
Iterator<Method> methodIterator = methods.iterator();
while (methodIterator.hasNext()) {
Method method = methodIterator.next();
CSVColumn csvColumn = method.getAnnotation(CSVColumn.class);
String header = csvColumn.name();
}
but how could I set the field name of the annotation to another value?
Should/could I declare some setter methods in the annotation class?
Use the utility class AnnotationUtil
You can do changeAnnotation(csvColumn, "name", "newName")

JsonInclude.Include.NON_DEFAULT not working with custom serializer

I want to both use a custom serializer and have the JsonInclude.Include.NON_DEFAULT designation be honored. When I don't use a custom serializer it is honored but when I do use a custom serializer it is not.
This is Jackson 2.2.2. I do not presently have the option to switch to a newer version of Jackson.
Here's a simple example that shows the problem:
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
import java.util.EnumSet;
import java.util.Set;
import java.util.stream.Collectors;
public class JacksonSerialization
{
public static void main(String[] args) throws Exception {
ObjectMapper serializer = new ObjectMapper();
Foo foo = new Foo();
foo.setFlags(EnumSet.of(Flag.CC, Flag.BB));
System.out.println(serializer.writeValueAsString(foo));
foo = new Foo();
System.out.println(serializer.writeValueAsString(foo));
}
public static enum Flag
{
AA,
BB,
CC
}
#JsonInclude(JsonInclude.Include.NON_DEFAULT)
public static class Foo
{
private Set<Flag> flags;
public Foo() {
flags = EnumSet.of(Flag.AA);
}
#JsonGetter("f")
#JsonSerialize(using = FlagSetSerializer.class)
public Set<Flag> getFlags() {
return flags;
}
public void setFlags(Set<Flag> theFlags) {
flags = theFlags;
}
}
public static class FlagSetSerializer extends JsonSerializer<Set<Flag>>
{
#Override
public void serialize(Set<Flag> value,
JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
String csv = value.stream()
.map(Flag::toString)
.collect(Collectors.joining(","));
jsonGenerator.writeString(csv);
}
}
}
And here's the output:
{"f":"BB,CC"}
{"f":"AA"}
Note that f is being serialized even when it has the default value. If I comment out the #JsonSerialize annotation then I get the following output:
{"f":["BB","CC"]}
{}
Then f properly does not get serialized. But of course things are not being serialized in the format I want.
So how do I get the custom serializer to honor the class's #JsonInclude annotation?
You probably want to implement public boolean isEmpty(SerializerProvider provider, T value) as per the documentation, which says:
public boolean isEmpty(SerializerProvider provider, T value)
Method called to check whether given serializable value is considered
"empty" value (for purposes of suppressing serialization of empty
values).
Default implementation will consider only null values to be
empty.
As per https://github.com/FasterXML/jackson-databind/issues/730
Another possible source of trouble is that you talk about NON_EMPTY but you code uses NON_DEFAULT.
And rather too much digging in the debugger leads me to suggest
#JsonSerialize(using = FlagSetSerializer.class, include = JsonSerialize.Inclusion.NON_DEFAULT)
Which seems to pass your tests.
The problem seems to be in JacksonAnnotationInspector#findSerializationInclusion, which first looks for a #JsonInclude attribute on the property, and when it fails to find that, it looks for a #JsonSerialize annotation. #JsonSerialize includes a deprecated include property, which has a default value of ALWAYS.
I've not looked into it too deeply, but I suspect a deprecation/refactor managed to slice off some functionality. C'est la vie.

How to create custom annotation in java?

I want to create custom annotation in java for DirtyChecking. Like I want to compare two string values using this annotation and after comparing it will return a boolean value.
For instance: I will put #DirtyCheck("newValue","oldValue") over properties.
Suppose I made an interface:
public #interface DirtyCheck {
String newValue();
String oldValue();
}
My Questions are:
Where I make a class to create a method for comparison for two string values? I mean, how this annotation notifies that this method I have to call?
How to retreive returning values of this method ?
First you need to mark if annotation is for class, field or method. Let's say it is for method: so you write this in your annotation definition:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface DirtyCheck {
String newValue();
String oldValue();
}
Next you have to write let's say DirtyChecker class which will use reflection to check if method has annotation and do some job for example say if oldValue and newValue are equal:
final class DirtyChecker {
public boolean process(Object instance) {
Class<?> clazz = instance.getClass();
for (Method m : clazz.getDeclaredMethods()) {
if (m.isAnnotationPresent(DirtyCheck.class)) {
DirtyCheck annotation = m.getAnnotation(DirtyCheck.class);
String newVal = annotation.newValue();
String oldVal = annotation.oldValue();
return newVal.equals(oldVal);
}
}
return false;
}
}
Cheers,
Michal
To answer your second question: your annotation can't return a value. The class which processes your annotation can do something with your object. This is commonly used for logging for example.
I'm not sure if using an annotation for checking if an object is dirty makes sense except you want to throw an exception in this case or inform some kind of DirtyHandler.
For your first question: you could really spent some effort in finding this yourself. There are enough information here on stackoverflow and the web.
CustomAnnotation.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface CustomAnnotation {
int studentAge() default 21;
String studentName();
String stuAddress();
String stuStream() default "CS";
}
How to use the field of Annotation in Java?
TestCustomAnnotation.java
package annotations;
import java.lang.reflect.Method;
public class TestCustomAnnotation {
public static void main(String[] args) {
new TestCustomAnnotation().testAnnotation();
}
#CustomAnnotation(
studentName="Rajesh",
stuAddress="Mathura, India"
)
public void testAnnotation() {
try {
Class<? extends TestCustomAnnotation> cls = this.getClass();
Method method = cls.getMethod("testAnnotation");
CustomAnnotation myAnno = method.getAnnotation(CustomAnnotation.class);
System.out.println("Name: "+myAnno.studentName());
System.out.println("Address: "+myAnno.stuAddress());
System.out.println("Age: "+myAnno.studentAge());
System.out.println("Stream: "+myAnno.stuStream());
} catch (NoSuchMethodException e) {
}
}
}
Output:
Name: Rajesh
Address: Mathura, India
Age: 21
Stream: CS
Reference

How to use an array constant in an annotation

I would like to use constants for annotation values.
interface Client {
#Retention(RUNTIME)
#Target(METHOD)
#interface SomeAnnotation { String[] values(); }
interface Info {
String A = "a";
String B = "b";
String[] AB = new String[] { A, B };
}
#SomeAnnotation(values = { Info.A, Info.B })
void works();
#SomeAnnotation(values = Info.AB)
void doesNotWork();
}
The constants Info.A and Info.B can be used in the annotation but not the array Info.AB as it has to be an array initializer in this place. Annotation values are restricted to values that could be inlined into the byte code of a class. This is not possible for the array constant as it has to be constructed when Info is loaded. Is there a workaround for this problem?
No, there is no workaround.
Why not make the annotation values an enum, which are keys to the actual data values you want?
e.g.
enum InfoKeys
{
A("a"),
B("b"),
AB(new String[] { "a", "b" }),
InfoKeys(Object data) { this.data = data; }
private Object data;
}
#SomeAnnotation (values = InfoKeys.AB)
This could be improved for type safety, but you get the idea.
It is because arrays' elements can be changed at runtime (Info.AB[0] = "c";) while the annotation values are constant after compile time.
With that in mind someone will inevitably be confused when they try to change an element of Info.AB and expect the annotation's value to change (it won't). And if the annotation value were allowed to change at runtime it would differ than the one used at compile time. Imagine the confusion then!
(Where confusion here means that there is a bug that someone may find and spend hours debugging.)
While there is no way to pass an array directly as an annotation parameter value, there is a way to effectively get similar behavior (depending on how you plan on using your annotations, this may not work for every use case).
Here's an example -- let's say we have a class InternetServer and it has a hostname property. We'd like to use regular Java Validation to ensure that no object has a "reserved" hostname. We can (somewhat elaborately) pass an array of reserved hostnames to the annotation that handles hostname validation.
caveat- with Java Validation, it would be more customary to use the "payload" to pass in this kind of data. I wanted this example to be a bit more generic so I used a custom interface class.
// InternetServer.java -- an example class that passes an array as an annotation value
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.Pattern;
public class InternetServer {
// These are reserved names, we don't want anyone naming their InternetServer one of these
private static final String[] RESERVED_NAMES = {
"www", "wwws", "http", "https",
};
public class ReservedHostnames implements ReservedWords {
// We return a constant here but could do a DB lookup, some calculation, or whatever
// and decide what to return at run-time when the annotation is processed.
// Beware: if this method bombs, you're going to get nasty exceptions that will
// kill any threads that try to load any code with annotations that reference this.
#Override public String[] getReservedWords() { return RESERVED_NAMES; }
}
#Pattern(regexp = "[A-Za-z0-9]{3,}", message = "error.hostname.invalid")
#NotReservedWord(reserved=ReservedHostnames.class, message="error.hostname.reserved")
#Getter #Setter private String hostname;
}
// NotReservedWord.java -- the annotation class
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#Target({FIELD, ANNOTATION_TYPE})
#Retention(RUNTIME)
#Constraint(validatedBy=ReservedWordValidator.class)
#Documented
public #interface NotReservedWord {
Class<? extends ReservedWords> reserved ();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String message() default "{err.reservedWord}";
}
// ReservedWords.java -- the interface referenced in the annotation class
public interface ReservedWords {
public String[] getReservedWords ();
}
// ReservedWordValidator.java -- implements the validation logic
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ReservedWordValidator implements ConstraintValidator<NotReservedWord, Object> {
private Class<? extends ReservedWords> reserved;
#Override
public void initialize(NotReservedWord constraintAnnotation) {
reserved = constraintAnnotation.reserved();
}
#Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
if (value == null) return true;
final String[] words = getReservedWords();
for (String word : words) {
if (value.equals(word)) return false;
}
return true;
}
private Map<Class, String[]> cache = new ConcurrentHashMap<>();
private String[] getReservedWords() {
String[] words = cache.get(reserved);
if (words == null) {
try {
words = reserved.newInstance().getReservedWords();
} catch (Exception e) {
throw new IllegalStateException("Error instantiating ReservedWords class ("+reserved.getName()+"): "+e, e);
}
cache.put(reserved, words);
}
return words;
}
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Handler {
enum MessageType { MESSAGE, OBJECT };
String value() default "";
MessageType type() default MessageType.MESSAGE;
}
As already was mentioned in previous posts, annotation vales are compile-time constants and there is no way to use an array value as a parameter.
I solved this problem a bit differently.
If you're owning the processing logic, take advantage of it.
For example, give an additional parameter to your annotation:
#Retention(RUNTIME)
#Target(METHOD)
#interface SomeAnnotation {
String[] values();
boolean defaultInit() default false;
}
Use this parameter:
#SomeAnnotation(defaultInit = true)
void willWork();
And this will be a marker to the AnnotationProcessor, which can do anything - initialize it with an array, use String[], or use Enums like Enum.values() and map them to String[].
Hope this will guide someone who has the similar situation in the right direction.

Categories