I'm reviewing how reflection works or possible work. I have this SomeClassBuilder wherein it has an attribute target : Target with declared annotation TargetAnnotation.
Thing is, is it possible to override/update the values/properties of Target wherein upon invoke of someMethod() would return the parameters on the annotation?
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface TargetAnnotation {
String first();
String second();
// other attributes
}
public class Target {
String first;
String second;
// some other attributes unique only to `Target`
}
public interface TargetHelper {
void setTarget(Target target);
}
public class SomeClassBuilder implements TargetHelper {
#TargetAnnotation(first = "first", second = "second")
private Target target;
#Override public void setTarget(Target target) { this.target = target }
public void someMethod() {
System.out.println(target.first); // should be `first`
System.out.println(target.second); // should be `second`
}
}
Or is it even possible to do it without TargetHelper interface?
Let's say I have this TargetProcessor called before SomeClassBuilder which sole purpose is to fill-in the target : Target annotated with #TargetAnnotation and assign the field/attributes from #TargetAnnotaton to Target.
public class TargetProcessor {
public void parse() {
// look into `#TargetAnnotation`
// map `#TargetAnnotation` properties to `Target`
}
}
You can achieve this by implementing Annotation Processor for your annotation #TargetAnnotation
For further readings and examples:
http://www.baeldung.com/java-annotation-processing-builder
https://github.com/bozaro/example-annotation-processor/blob/master/example-modify/processor/src/main/java/ru/bozaro/processor/HelloProcessor.java
https://deors.wordpress.com/2011/10/08/annotation-processors/
This article explains, how it should be done:
http://hannesdorfmann.com/annotation-processing/annotationprocessing101
Here is my code
import static xdean.jex.util.lang.ExceptionUtil.uncheck;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.util.stream.Stream;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import xdean.jex.util.reflect.ReflectUtil;
public class Q46765735 {
public static void main(String[] args) {
create(TargetDomain.class).printTarget();
}
public static <T> T create(Class<T> clz) {
T target = uncheck(() -> clz.newInstance());
Stream.of(ReflectUtil.getAllFields(clz, false)).forEach(f -> uncheck(() -> fill(target, f)));
return target;
}
private static <T> void fill(T target, Field field) throws Exception {
TargetAnnotation anno = field.getAnnotation(TargetAnnotation.class);
if (anno == null) {
return;
}
Class<?> type = field.getType();
if (!Target.class.isAssignableFrom(type)) {
return;
}
field.setAccessible(true);
Target value = (Target) field.get(target);
if (value == null) {
value = (Target) type.newInstance();
}
value.setFirst(anno.first());
value.setSecond(anno.second());
field.set(target, value);
}
}
#Retention(RetentionPolicy.RUNTIME)
#java.lang.annotation.Target({ ElementType.FIELD })
#interface TargetAnnotation {
String first();
String second();
}
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
class Target {
String first;
String second;
}
class TargetDomain {
#TargetAnnotation(first = "first", second = "second")
private Target target = new Target("a", "b");
public void printTarget() {
System.out.println(target.first); // should be `first`
System.out.println(target.second); // should be `second`
}
}
Tips:
You can replace lombok by write constructor and getter/setter manually.
ReflectUtil.getAllFields get all fields of the class.
uncheck simply ignore exceptions, you can use try-catch.
Related
Using Jackson, is there a way to deserialize a proprty that depends on the value of another property?
if i have this json {"foo":"a","bar":"b"} i'd like to deserialize it to the Test class below as Test [foo=a, bar=b_a], where bar is the value of the json property "bar" and the value of the property "foo".
Of course this is a trivial example, the real deal would be to deserialize a datamodel entity: {"line":"C12", "machine": {"line":"C12", "code":"A"}} machine.line and line are always the same, and i'd like to express it like this: {"line":"C12", "machine": "A"}
import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
public abstract class Main{
private static class Test {
#JsonProperty
private String foo;
#JsonProperty
#JsonDeserialize(using = CustomDeserializer.class)
private String bar;
// ...other fields to be deserialized with default behaviour
private Test() {
}
public Test(String a, String bar) {
this.foo = a;
this.bar = bar;
}
#Override
public String toString() {
return "Test [foo=" + foo + ", bar=" + bar + "]";
}
}
private static class CustomDeserializer extends StdDeserializer<String> {
protected CustomDeserializer() {
super(String.class);
}
#Override
public String deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
String foo = //how to get foo property?
String value = p.getValueAsString();
if (!foo.isEmpty()) {
return value + "_" + foo;
} else {
return value;
}
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Test foo2 = mapper.readValue("{\"foo\":\"a\",\"bar\":\"b\"}", Test.class);
System.out.println(foo2); // Test [foo=a, bar=b_a]
}
}
One way to solve your problem is specify a custom deserializer that involves your Test class instead of your string field because the deserialization of your property is based on the value of another property:
public class CustomDeserializer extends JsonDeserializer<Test> {}
#JsonDeserialize(using = CustomDeserializer.class)
public class Test {}
Then you can deserialize your object reading the JsonNode tree built from your input string:
public class CustomDeserializer extends JsonDeserializer<Test> {
#Override
public Test deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String foo = node.get("foo").asText();
String bar = node.get("bar").asText();
if (!foo.isEmpty()) {
bar = (bar + '_' + foo);
}
return new Test(foo, bar);
}
}
//your example
public class Main {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Test foo2 = mapper.readValue("{\"foo\":\"a\",\"bar\":\"b\"}", Test.class);
System.out.println(foo2); // Test [foo=a, bar=b_a]
}
}
I got a similar problem today and I wanted to share my solution. So instead of using a #JsonDeserialize, I use a #JsonCreator on the parent object with a package private constructor to accept the "raw" properties and then I can process this data and return better objects.
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
class Scratch {
public static void main(String[] args) throws Exception{
final var testData = "{\"foo\":\"a\",\"bar\":\"b\"}";
final var mapper = new ObjectMapper();
final var testObj = mapper.readValue(testData, Test.class);
System.out.println(testObj); // Test[foo=a, bar=a_b]
}
record Test (
String foo,
String bar
){
#JsonCreator Test(
#JsonProperty("foo") String foo,
#JsonProperty("bar") String bar,
#JsonProperty("_dummy") String _dummy // extra param for the constructor overloading
) {
this(foo, deserializeBar(foo, bar));
}
private static String deserializeBar(String foo, String bar) {
if (foo == null || foo.isEmpty()) {
return bar;
}
return "%s_%s".formatted(foo, bar);
}
}
}
In the end, I've resorted using BeanDeserializerModifier
Please notice that the following code is not fully functioning because it relies on code I'm not allowed to share, but it should suffice to get the idea.
package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
public class JsonDelegateDeserializerModule extends SimpleModule {
// !! must be registered as guice factory
public interface JsonDelegateDeserializerFactory {
JsonDelegateDeserializerModule create(String packagePath);
}
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface JsonDelegateDeserializer {
public Class<? extends StdDeserializer<?>> deserializer();
public Class<?> forType();
}
protected interface JsonDeserializerFactory {
// non metto nessun generic in TagHandler o guice non riesce piu a creare la
// factory!
#SuppressWarnings("rawtypes")
public JsonDeserializer create(JsonDeserializer baseDeserializer);
}
private static final Logger LOGGER = LoggerFactory.getLogger(JsonDelegateDeserializerModule.class);
#Inject
private FactoryInjector injector;
private final String packagePath;
#AssistedInject
protected JsonDelegateDeserializerModule(#Assisted String packagePath) {
super();
this.packagePath = packagePath;
}
#Override
public String getModuleName() {
return JsonDelegateDeserializerModule.class.getSimpleName() + "[" + packagePath + "]";
}
#Override
public Object getTypeId() {
return JsonDelegateDeserializerModule.class.getSimpleName() + "[" + packagePath + "]";
}
#Override
public void setupModule(SetupContext context) {
Reflections reflectios = new Reflections(packagePath, new SubTypesScanner(), new TypeAnnotationsScanner());
Map<Class<?>, JsonDeserializerFactory> classToDeserializerFactory = new HashMap<>();
Set<Class<?>> classesWithModifier = reflectios.getTypesAnnotatedWith(JsonDelegateDeserializer.class);
for (Class<?> classWithModifier : classesWithModifier) {
JsonDelegateDeserializer annotation = classWithModifier.getAnnotation(JsonDelegateDeserializer.class);
if (annotation != null) {
Class<? extends StdDeserializer<?>> deserializerType = annotation.deserializer();
Class<?> forType = annotation.forType();
try {
JsonDeserializerFactory factory = injector.getFactory(JsonDeserializerFactory.class,
deserializerType);
classToDeserializerFactory.put(forType, factory);
} catch (Exception e) {
LOGGER.error("Exception was thown while creating deserializer {} for type {}:", deserializerType,
forType, e);
throw new RuntimeException(e);
}
}
}
if (!classToDeserializerFactory.isEmpty()) {
setDeserializerModifier(new BeanDeserializerModifier() {
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc,
JsonDeserializer<?> deserializer) {
List<Class<?>> possibleTypesList = new LinkedList<>();
if (deserializer instanceof BeanDeserializer) {
for (Entry<Class<?>, JsonDeserializerFactory> entry : classToDeserializerFactory.entrySet()) {
Class<?> type = entry.getKey();
if (type.isAssignableFrom(deserializer.handledType())) {
possibleTypesList.add(type);
}
}
if (possibleTypesList.size() > 1) {
possibleTypesList.sort(new Comparator<Class<?>>() {
#Override
public int compare(Class<?> o1, Class<?> o2) {
if (o1.isAssignableFrom(o2)) {
return 1;
} else {
return -1;
}
}
});
}
Class<?> type = Utils.first(possibleTypesList);
if (type == null) {
return super.modifyDeserializer(config, beanDesc, deserializer);
} else {
JsonDeserializerFactory factory = classToDeserializerFactory.get(type);
JsonDeserializer<?> modifiedDeserializer = factory.create(deserializer);
return super.modifyDeserializer(config, beanDesc, modifiedDeserializer);
}
} else {
// รจ gia stato impostato un deserializzatore piu specifico, non imposato questo
return super.modifyDeserializer(config, beanDesc, deserializer);
}
}
});
}
super.setupModule(context);
}
}
then you can simply annotate the Mixin to add the custom deserializer
#JsonDelegateDeserializer(deserializer = LoadLineDeserializer.class, forType = Line.class)
public interface LineMixIn {
public static class LoadLineDeserializer extends DelegatingDeserializer {
#AssistedInject
public LoadLineDeserializer(#Assisted JsonDeserializer baseDeserializer, LineService lineService) {
super(baseDeserializer);
}
// ...
}
// ...
}
I am trying to read a YAML file and store the result in a list of POJOs.
I cannot modify the YAML file. I use Jackson 2.10.0 but I am open to any other version. I am trying to parse the following script with Jackson:
vehicles-notype.yaml
Vehicles is basically a list of objects with some common properties and some unique to the type of vehicle.
---
vehicles:
- car:
make: "Mercedes-Benz"
model: "S500"
topSpeed: 250.0
seatingCapacity: 5
- truck:
make: "Isuzu"
model: "NQR"
payloadCapacity: 7500.0
Desired outpout
After reading the file, I'd like that, if I introspect the list, I'd like to get:
... App.java:48): -> start()
... App.java:56): class net.jgp.labs.jackson.yaml.lab411_pojos.Car
... App.java:56): class net.jgp.labs.jackson.yaml.lab411_pojos.Truck
The Car and Truck POJOs are pretty obvious:
Car
package net.jgp.labs.jackson.yaml.lab411_pojos;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Car extends Vehicle {
private int seatingCapacity;
private double topSpeed;
#JsonCreator
public Car(
#JsonProperty("make") String make,
#JsonProperty("model") String model,
#JsonProperty("seating") int seatingCapacity,
#JsonProperty("topSpeed") double topSpeed) {
super(make, model);
this.seatingCapacity = seatingCapacity;
this.topSpeed = topSpeed;
}
public int getSeatingCapacity() {
return seatingCapacity;
}
public void setSeatingCapacity(int seatingCapacity) {
this.seatingCapacity = seatingCapacity;
}
public double getTopSpeed() {
return topSpeed;
}
public void setTopSpeed(double topSpeed) {
this.topSpeed = topSpeed;
}
public String getType() {
return "car";
}
}
Truck
package net.jgp.labs.jackson.yaml.lab411_pojos;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Truck extends Vehicle {
private double payloadCapacity;
#JsonCreator
public Truck(
#JsonProperty("make") String make,
#JsonProperty("model") String model,
#JsonProperty("payload") double payloadCapacity) {
super(make, model);
this.payloadCapacity = payloadCapacity;
}
public double getPayloadCapacity() {
return payloadCapacity;
}
public void setPayloadCapacity(double payloadCapacity) {
this.payloadCapacity = payloadCapacity;
}
#Override
public String getType() {
return "truck";
}
}
Fleet
The Fleet POJO is also obvious.
package net.jgp.labs.jackson.yaml.lab411_pojos;
import java.util.List;
public class Fleet {
private List<Vehicle> vehicles;
public void setVehicles(List<Vehicle> vehicles) {
this.vehicles= vehicles;
}
public List<Vehicle> getVehicles() {
return vehicles;
}
}
Vehicle
Vehicle is a bit more tricky, as I am trying to play with #JsonTypeInfo and #JsonSubTypes. You can see the commented code, which is slowly driving me mad:
package net.jgp.labs.jackson.yaml.lab411_pojos;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
#JsonTypeInfo(
use = JsonTypeInfo.Id.CLASS,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY
// ,
// property = "className"
)
#JsonSubTypes({
#Type(value = Car.class, name = "car"),
#Type(value = Truck.class, name = "truck")
})
//#JsonSubTypes({
// #Type(value = Car.class, name = "car"),
// #Type(value = Truck.class, name = "truck")
//})
public abstract class Vehicle {
private String make;
private String model;
#JsonProperty("type")
abstract public String getType();
public void setType(String type) {};
protected Vehicle(String make, String model) {
this.make = make;
this.model = model;
}
public String getMake() {
return make;
}
public void setMake(String make) {
this.make = make;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
App
Finally the application code, which is pretty obvious too.
package net.jgp.labs.jackson.yaml.lab411_read_diff_objects;
import java.io.File;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import net.jgp.labs.jackson.yaml.lab411_pojos.Fleet;
import net.jgp.labs.jackson.yaml.lab411_pojos.Vehicle;
/**
* What does it do?
*
* #author jgp
*/
public class ReadListVehicleNoTypeApp {
private static final Logger log =
LoggerFactory.getLogger(ReadListVehicleNoTypeApp.class);
/**
* main() is your entry point to the application.
*
* #param args
*/
public static void main(String[] args) {
ReadListVehicleNoTypeApp app = new ReadListVehicleNoTypeApp();
try {
app.start();
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* The processing code.
*
* #throws IOException
*/
protected boolean start() throws IOException {
log.debug("-> start()");
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
Fleet fleet = mapper.readValue(new File("data/vehicles-notype.yaml"),
Fleet.class);
for (Vehicle v : fleet.getVehicles()) {
log.debug("{}", v.getClass());
}
return true;
}
}
I am pretty sure there is something to play with the #Json family of attributes, but I am slowly losing it ;-).
car and truck are a field names, properties. I am not aware about Jackson annotation which allows to set types from different fields.
If Yaml file can not be modified, we can use Streaming API to read type property and deserialise Vehicle. In pseudocode it could look like:
while token != EOF
while token != FIELD_NAME
nextToken()
fieldName = nextFieldName();
clazz = convertToClass(fieldName);
vehicles.add(read(clazz));
Luckily, field name which defines type is a first field name and we can read it manually and use Jackson to read type after that. I removed JsonSubTypes and JsonTypeInfo annotation from Vehicle class and with Streaming API it could look like below:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class YamlApp {
public static void main(String[] args) throws Exception {
File yamlFile = new File("./resource/test.yaml").getAbsoluteFile();
FleetDeserializer deserializer = new FleetDeserializer();
Fleet fleet = deserializer.readValue(yamlFile);
System.out.println(fleet);
}
}
class FleetDeserializer {
private YAMLFactory factory = new YAMLFactory();
private ObjectMapper mapper = new ObjectMapper(factory);
public Fleet readValue(File yamlFile) throws IOException {
Fleet fleet = new Fleet();
fleet.setVehicles(new ArrayList<>());
YAMLParser parser = factory.createParser(yamlFile);
while (parser.nextToken() != null) {
if (parser.getCurrentToken() != JsonToken.START_OBJECT) {
continue;
}
// skip everything until a field name
while (parser.nextToken() != JsonToken.FIELD_NAME) ;
Class<? extends Vehicle> type = getType(parser.getCurrentName());
if (type == null) {
continue;
}
// skip field name
parser.nextToken();
parser.nextToken();
// read next vehicle
fleet.getVehicles().add(mapper.readValue(parser, type));
}
return fleet;
}
private Class<? extends Vehicle> getType(String fieldName) {
Objects.requireNonNull(fieldName);
switch (fieldName) {
case "car":
return Car.class;
case "truck":
return Truck.class;
default:
return null;
}
}
}
Above code prints:
Fleet{vehicles=[Car{seatingCapacity=5, topSpeed=250.0, make='Mercedes-Benz', model='S500'}, Truck{payloadCapacity=7500.0, make='Isuzu', model='NQR'}]}
I am working with XML like:
<localMSZ>
<territories>
<codeOKTMO>str1</codeOKTMO>
<codeOKTMO>str2</codeOKTMO>
</territories>
</localMSZ>
In Java code I have class LocalMSZ which have List of String like:
class LocalMSZ {
List<String> territories;
}
I doesn't understand how I should post annotation in this case?
The problem is in your mapping class: it lacks the structure and annotations needed for this. It should work with this:
import java.util.LinkedList;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import com.thoughtworks.xstream.converters.extended.ToAttributedValueConverter;
#XStreamAlias("localMSZ")
public class LocalMSZ {
private Territories territories = new Territories();
public Territories getTerritories() {
return territories;
}
public void setTerritories(Territories territories) {
this.territories = territories;
}
#XStreamAlias("codeOKTMO")
#XStreamConverter(value = ToAttributedValueConverter.class, strings = { "value" })
public static class Code {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
#XStreamAlias("territories")
public static class Territories {
// This one maps the sequence of <codeOKTMO> tags
#XStreamImplicit
private List<Code> codes = new LinkedList<Code>();
public List<Code> getCodes() {
return codes;
}
public void setCodes(List<Code> codes) {
this.codes = codes;
}
}
}
Remember also when you write your main method to process the annotations of LocalMSZ
XStream xstream = new XStream();
xstream.processAnnotations(LocalMSZ.class);
...
I am very new to usage of annotation.
can anyone please tell me how can we declare an annotation and also call all the methods / variables that are declared with that annotation
am using java to implement this annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
#Target(ElementType.FIELD)
public #interface isAnnotatedVariable {
String varName();
}
and used the annotation in
public class Example {
#isAnnotatedVariable(varName = "S")
public String var;
#isAnnotatedVariable(varName = "S")
public String var1;
}
and tried to get the variable names using
public class BuildStepClassDetector {
public static void main(String[] args) throws IOException {
BuildStepClassDetector build = new BuildStepClassDetector();
final Logger4J logger = new Logger4J(build.getClass().getName());
final HashMap<String, Class<?>> isAnnotatedVariables = new HashMap<String, Class<?>>();
final TypeReporter reporter = new TypeReporter() {
#SuppressWarnings("unchecked")
#Override
public Class<? extends Annotation>[] annotations() {
return new Class[] { isAnnotatedVariable.class };
}
#SuppressWarnings("unchecked")
#Override
public void reportTypeAnnotation(Class<? extends Annotation> arg0, String arg1) {
Class<? extends isAnnotatedVariable> isAnnotatedVariableClass;
try {
isAnnotatedVariableClass = (Class<? extends isAnnotatedVariable>) Class.forName(arg1);
isAnnotatedVariables.put(
isAnnotatedVariableClass.getAnnotation(isAnnotatedVariable.class).varName(),
isAnnotatedVariableClass);
} catch (ClassNotFoundException e) {
logger.getStackTraceString(e);
}
}
};
final AnnotationDetector cf = new AnnotationDetector(reporter);
cf.detect();
System.out.println(isAnnotatedVariables.keySet());
}
}
Here is a simple example for declaring annotation and retrieving a annotated field using Reflection.
package asif.hossain;
import java.lang.annotation.*;
import java.lang.reflect.Field;
/**
*
* Created by sadasidha on 21-Aug-14.
*/
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
#interface MyAnnotation {
public String value();
}
class TestClass
{
#MyAnnotation("This is a name field")
public String name;
}
public class Main {
public static void main(String ... args) throws IllegalAccessException {
TestClass testObject = new TestClass();
Field[] fields = testObject.getClass().getFields();
for (Field field : fields)
{
Annotation annotation = field.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation)
{
System.out.println(field.getName());
// get field value
String value = (String)field.get(testObject);
System.out.println("Field Value = "+ value);
//Set field value
field.set(testObject,"Your Name");
System.out.println(testObject.name);
}
}
}
}
You can follow this tutorial http://tutorials.jenkov.com/java-reflection/index.html to learn more about annotation and reflection.
For the first time I dealing with Java Annotations. So please pardon me if I m doing anything wrong ! But this class compiled successfully using javac MyFirstAnnotation.java
but when I try to run this source code using java TestMyAnnotation
it throws an error like this
package Annotations;
import java.lang.annotation.*;
import java.util.*;
import java.lang.reflect.*;
#Documented
#Target(ElementType.METHOD)
#Inherited
#Retention(RetentionPolicy.RUNTIME)
public #interface MyFirstAnnotation
{
String author() default "Chiranjib Nandy";
int revisionNumber() default 1;
String date();
}
class MySuperClass
{
public String showMe()
{
return "Do Something";
}
}
class MyAnnotation extends MySuperClass
{
#Override
#MyFirstAnnotation(author="Recmach",revisionNumber=2,date="1st June,2014")
public String showMe()
{
return "Display Something";
}
#Deprecated
#MyFirstAnnotation(revisionNumber=2,date="2nd June,2014")
public void oldMethod()
{
System.out.println("It is a deprecated method");
}
#SuppressWarnings({"unused","deprecation"})
#MyFirstAnnotation(author="Papai",date="1st June,2014")
public void myMethod()
{
int j;
oldMethod();
System.out.println("It is defined in my way");
}
}
class TestMyAnnotation
{
public static void main(String[] args) throws ClassNotFoundException
{
Method myMethods[]=Class.forName("Annotations.MyAnnotation").getDeclaredMethods();
for(Method m : myMethods)
{
Annotation[] annotations=m.getDeclaredAnnotations();
for(Annotation anno : annotations)
{
if(anno instanceof MyFirstAnnotation)
{
MyFirstAnnotation myFirstAnnotation = (MyFirstAnnotation) anno;
System.out.println("name : "+myFirstAnnotation.author());
System.out.println("name : "+myFirstAnnotation.revisionNumber());
System.out.println("name : "+myFirstAnnotation.date());
}
}
}
}
}
Three issues that I fixed.
The public class needs to be TestMyAnnotation.
This line should be MyAnnotation, not what it was before
Method myMethods[]=Class.forName("MyAnnotation").getDeclaredMethods();
The first class at the top should not be public, because you cannot have two public classes inside one file.
Take the following code and put it inside TestMyAnnotation.java. Then run javac TestMyAnnotation.java, followed by java TestMyAnnotation.
import java.lang.annotation.*;
import java.util.*;
import java.lang.reflect.*;
#Documented
#Target(ElementType.METHOD)
#Inherited
#Retention(RetentionPolicy.RUNTIME)
#interface MyFirstAnnotation
{
String author() default "Chiranjib Nandy";
int revisionNumber() default 1;
String date();
}
class MySuperClass
{
public String showMe()
{
return "Do Something";
}
}
class MyAnnotation extends MySuperClass
{
#Override
#MyFirstAnnotation(author="Recmach",revisionNumber=2,date="1st June,2014")
public String showMe()
{
return "Display Something";
}
#Deprecated
#MyFirstAnnotation(revisionNumber=2,date="2nd June,2014")
public void oldMethod()
{
System.out.println("It is a deprecated method");
}
#SuppressWarnings({"unused","deprecation"})
#MyFirstAnnotation(author="Papai",date="1st June,2014")
public void myMethod()
{
int j;
oldMethod();
System.out.println("It is defined in my way");
}
}
public class TestMyAnnotation
{
public static void main(String[] args) throws ClassNotFoundException
{
Method myMethods[]=Class.forName("MyAnnotation").getDeclaredMethods();
for(Method m : myMethods)
{
Annotation[] annotations=m.getDeclaredAnnotations();
for(Annotation anno : annotations)
{
if(anno instanceof MyFirstAnnotation)
{
MyFirstAnnotation myFirstAnnotation = (MyFirstAnnotation) anno;
System.out.println("name : "+myFirstAnnotation.author());
System.out.println("name : "+myFirstAnnotation.revisionNumber());
System.out.println("name : "+myFirstAnnotation.date());
}
}
}
}
}
Hope this link helps.
http://www.shivasoft.in/blog/java/compile-and-run-java-program-in-package-from-command-line/
This is already in stack overflow. You have to compile your class with package like in this post.
try run your Main Java class with adding -cp (classpath) like below commands:
java -cp . TestMyAnnotation
Hope it helps.