Let us consider that I have a file which looks like following:
#CreateFieldClass
public class Queue {
private String queueId;
private int order;
private boolean isActive;
/* Getters and Setters */
}
What I want is, If there is #CreateFieldClass annotation, I want to generat a new java file, in the same package which would look something like this
public class QueueFields {
public static final Field<Queue, String> QUEUE_ID = new Field<>(Queue.class, "queueId", DataType.STRING);
public static final Field<Queue, Integer> ORDER = new Field<>(Queue.class,"order", DataType.NUMBER);
public static final Field<Queue, Boolean> IS_ACTIVE = new Field<>(Queue.class,"isActive", DataType.Boolean);
}
I have a mapping of Java type to the "DataType" mentioned above.
I know ASM is one option to consider, but are there any better recommendations or even some ASM tutorials/examples someone can help me out.
To examine the annotated class, you can use reflection. Be aware that any fields that use generics will lose the generic parameter types due to erasure (if you need to get around that, then you need to parse the source code and work off of the parse tree). To generate the resulting class, you can do basic String concatenation. If you want a more structured method for generating code, I like the codemodel library.
Related
I went through some of the samples that have used libraries to generate bean classes from JSON, XML etc. What I would like to know is, whether there's a way to dynamically generate a java bean class, with the parameters I give?
For example if I give an array of Strings as arguments which would represent the properties of the Pojo class for now, how can I generate the POJO?
Arguments: {"field1", "field2", "field3"}
Generate POJO would be:
public class TestBean {
private String field1;
TestBean() {
}
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
}
It should be the same for field2 and field3 as well.
Here I'm assuming that all the properties above are String and the class name is constant for now. Is there any way I can achieve this? Thanks in advance.
The problem with generating an actual Java class at runtime is that there is no way you can access it using standard Java syntax as the compiler doesn't know about it.
In practice therefore, most people just use a map in this circumstance. The only case I can think where you would need to generate a real class is where there is some other code you can't change that requires a Java object and inspects it dynamically using reflection or otherwise.
If you don't need this you are better off using a map, or possibly some utility class designed to emulate a Java Bean.
The Apache BeanUtils package provides the DynaBean interface to implement dynamic Java Beans. That said, the classes are only recognised as beans if accessed from the rest of the BeanUtils package.
There are several subclasses depending on what you want, for example, LazyDynaBean:
DynaBean myBean = new LazyDynaBean();
myBean.set("myProperty", "myValue");
I'm new to annotation processing and code generation. I want to find out how can I perform such operation like appending new method to existing class. Here is an example of what I want to do:
Assume that we have a class with with custom annotations like this one:
class SourceClass {
#CustomAnnotation
fun annotatedFun1(vararg argument: Any) {
//Do something
}
#CustomAnnotation
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
And the result I want to get - extended copy of that class:
class ResultClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
fun annotatedFun1(vararg argument: Any) {
//Do something
}
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
I've already found out how to create annotation processor. I'm looking for a method to save all existing fields, properties and methods in source class and to append a few more methods to it.
If it is possible to modify class without creating new one - it would be perfect, but in all tutorials only new classes are created and I didn't find any example where all contents of source class are being copied to another one.
Please, do not advise to use reflection. I need this for android and so reflection is not the option cause of resources cost. I'm looking for compile-time solution.
It is required for custom script language implemented in app and should be used to simplify wrapper classes structure. When this job is done directly in code - it looks awful when such method count exceeds 20 per class.
Here is a good example of Java Annotation Processing I recently worked with.
It's an implementation of #Immutable annotation.
Check out ByteBuddy or Kotlin Poet to understand how additional code generation works.
For Kotlin you do almost the same, check this manual for Kotlin-specific steps.
With Kotlin, you can use extension functions and that is the recommended way of adding new functionality to existing classes that you don't control. https://kotlinlang.org/docs/reference/extensions.html
You may be abel to follow the pattern used by Project Lombok. See How does lombok work? or the source code for details.
Another option would be to write a new class that extends your source class:
class ResultClass : SourceClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
}
Or perhaps use composition instead and implemnent cover methods for all the public methods in SourceClass.
If you are not tied to doing this using annotation processing, you could use a separate piece of custom code to process the source code files before compiling. Maybe use a regular expression like /#CustomAnnotation\s+.*fun (\w+)\s*\(([^)]*)\)/gm (Test on Regex101) to find the annotated methods.
If I understood the requirement correctly, the goal is to implement something like described below.
You have a source file C.java that defines the class C like this:
public final class C
{
#Getter
#Setter
private int m_IntValue;
#Getter
#Constructor
private final String m_Text;
}
And now you want to know how to write an annotation processor that jumps in during compilation and modifies the source from C.java that the compiler sees to something like this:
public final class C
{
private int m_IntValue;
public final int getIntValue() { return m_IntValue; }
public final void setIntValue( final int intValue ) { m_IntValue = intValue; }
private final String m_Text;
public final String getText() { return m_Text; }
public C( final String text ) { m_Text = text; }
}
The bad news is, that this is not possible … not with an annotation processor, not for Java 15.
For Java 8 there was a way, using some internal classes with reflection to convince the AP to manipulate the already loaded source code in some way and let the compiler compile it a second time. Unfortunately, it failed more often than it worked …
Currently, an annotation processor can only create a new (in the sense of additional) source file. So one solution could be to extend the class (of course, that would not work for the sample class C above, because the class itself is final and all the attributes are private …
So writing a pre-processor would be another solution; you do not have a file C.java on your hard drive, but one named C.myjava that will be used by that preprocessor to generate C.java, and that in turn is used by the compiler. But that is not done by an annotation processor, but it may be possible to abuse it in that way.
You can also play around with the byte code that was generated by the compiler and add the missing (or additional) functionality there. But that would be really far away from annotation processing …
As a summary: today (as of Java 15), an annotation processor does not allow the manipulation of existing source code (you cannot even exclude some source from being compiled); you can only generate additional source files with an annotation processor.
Throughout my app, I request JSON data from my web server and the response is almost always in a different.
For example, one response might look like this:
{"success":true,"data":{"token_id":"pPt9AKl0Cg","token_key":"8ax224sFrJZZkStAQuER"}}
While another might look like this:
{"success":true,"data":{"user_id":"20","username":"Bob"}}
And another might look like this:
{"success":true,"data":{"user_id":"20","stats":{"followers":"500","following":"12"}}}
Previously, I created a model class (Java) for each different response type. For example, for the first response above, my model class might look like this:
public class MyResponseModel {
private boolean success;
private DataModel data;
public static class DataModel {
private String token_id;
private String token_key;
}
...
}
Is this really the best way of doing this? Because if I do this for the dozen+ responses I get across my app, I'll end up with a dozen+ different model classes, one for each different response.
Are there alternatives to parsing JSON?
Thanks.
You will need one DTO or model class for each type of response. The static typing is required to serialize/deserialize from/to json. You can use generics to wrap the response. Refactoring your code this will be something like:
public class MyResponseModel <T> {
private boolean success;
private T data;
}
public class DataModel {
private String token_id;
private String token_key;
}
Then your code can return MyResponseModel<DataModel> object for this scenario.
If you really want to use one class for every type of response you will need to represent all your response as key value pairs and then you can have one class containing a Map. I will not recommend that approach and would prefer to have one class for each type of response.
Check out https://github.com/jayway/JsonPath , it`s only in the Java world where the default solution is to serialize/deserialize.
How do you set variables which contain the class name, like TAG in android.util.Log, while respecting Dont-Repeat-Yourself?
These are some possibilities:
In Google code, it is often used like
public class Classname {
public final String TAG = "Classname";
which repeats the classname and was not refactor-renamed correctly in AndroidStudio (no Strings were).
Then, there is a dynamic variant
public class Classname {
public final String TAG = getClass().getName();
which does not repeat the Classname, thus seems better, yet is less readable.
Or, you could make TAG static (this might be premature optimization). Apart from the official version above, you could get the name in code like
public class Classname {
public final static String TAG
= new Object() { }.getClass().getEnclosingClass().getName();
which is way less readable, and does have problems with inheritance (being static).
What is the best practice concerning this?
Is there a better way than 1-3? (Or is this a wrong approach?)
I have gone with the dynamic approach in the past:
public class Classname {
public final String TAG = getClass().getName();
It is not that unreadable, and it is self-contained.
For more complex cases of DRY-ness, there is always the possibility of creating your own annotations, and then either
Use a two-step compile process to first generate non-DRY sources and then compile them into non-DRY .class files.
Use the annotations in an initialization step within your program to fill in the non-DRY parts at run-time, before running any logic that depends on those parts.
Using the second approach, you could have something like
#ReplaceWithClassName("TAG")
public class Classname {
public final String TAG;
And then you would iterate through all classes annotated with #ReplaceWithClassName filling in the blanks as an initialization step (more on iterating through annotated classes here; more on changing a final String here).
Annotations, introspection and code-generation provide great flexibility and power. Therefore, use wisely if you use them at all. For this particular case, the "dynamic approach" is much more readable.
retrieve class name dynamically
#JeffMiller gave the example in the ClassLogger class of his sormula project. In the class Logger, he uses
StackTraceElement[] stes = new Throwable().getStackTrace();
int e = stes.length - 1;
for (int i = 0; i < e; ++i) {
if (stes[i].getClassName().equals(classLoggerClassName)) {
// next on stack is the class that created me
log = LoggerFactory.getLogger(stes[i + 1].getClassName());
break;
}
}
to get the caller's class name.
use the class to get its name
#FlorentBayle said in the comments that
public final static String TAG = Classname.class.getName();
should be refactored correctly. (And is more readable than variant 3 above).
This is also the approach used by third-party logging frameworks like SLF4J. It is initialized via
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
I have a bunch of constants throughout my code for various adjustable properties of my system. I'm moving all of them to a central .properties file. My current solution is to have a single Properties.java which statically loads the .properties file and exposes various getter methods like this:
public class Properties {
private static final String FILE_NAME = "myfile.properties";
private static final java.util.Properties props;
static {
InputStream in = Properties.class.getClassLoader().getResourceAsStream(
FILE_NAME);
props = new java.util.Properties();
try {
props.load(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String getString(Class<?> cls, String key) {
return props.getProperty(cls.getName() + '.' + key);
}
public static int getInteger(Class<?> cls, String key) {
return Integer.parseInt(getString(cls, key));
}
public static double getDouble(Class<?> cls, String key) {
return Double.parseDouble(getString(cls, key));
}
}
The only problem with that is that for every constant that I get from this file, I have some boilerplate:
private final static int MY_CONSTANT = Properties.getInteger(
ThisClass.class, "MY_CONSTANT");
I don't think I want to use Spring or the like as that seems like even more boilerplae. I was hoping to use a custom annotation to solve the issue. I found this tutorial, but I can't really sort out how to get the functionality that I want out of the annotation processing. The Java docs were even less helpful. This should be a thing I should be able to do at compile time, though. I know the names of the class and field.
What I'm thinking is something like this:
#MyAnnotation
private static final int MY_CONSTANT;
Anyone know how I would go about doing this or at least best practices for what I want to do?
First of all, you shouldn't do it. It's practical, but too hacky and if you ever want to write a test using different settings, you'll run into problems. Moreover, nobody's gonna understand how it works.
An annotation processor can probably do nothing for you. A Lombok-style-hacking processor can. You want to make
#MyAnnotation
private static final int MY_CONSTANT;
work like
private final static int MY_CONSTANT =
Properties.getInteger(ThisClass.class, "MY_CONSTANT");
The original expression doesn't compile (due to the uninitialized final variable), but it parses fine and Lombok can do its job. There's already something related there:
#Value changes the modifiers to final private
#UtilityClass makes all fields static
So actually, you could write just
#MyAnnotation
int MY_CONSTANT;
and let your annotation change also the modifiers. I'd look at the eclipse and javac handlers for #UtilityClass, I guess all you need is to generate the initializer (which is quite some work because it's all damn complicated).
I don't think Lombok itself will implement this anytime soon, since
all the static stuff is non-testable and mostly bad style
and not everyone wants this in their code
it's not that much boilerplate
it also magically refers to the class Properties, but this could be solved via configuration
but I guess a contribution might be accepted.
Actually not quite clear why and what do you want to archive.
As I correctly undestand, you want use special kind of annotations to automatically assign values for static final constants from some properties file. Unfortunatelly it is impossible without special hacks. And annotations have nothing to do with this.
The reason is that final fields must be initialized and it is compiler's request. There aren't special annotations in java which will provide such syntactic sugar which you want.
But if you insist on this there are two ways:
Extrim way. Init all properties field with default value. Then using this hack in some static init section initialize this value using reflection mechanism and you code via reading values from properties.
Less extrim way: refuse request of final modifiers for properties fields, and using only reflection fill these fields values.
And additionally, for these ways, yes you can use annotations. But you will have to solve following technical issues:
1) Find all fields in all classes in classpath, which are annotated with you special annotation. Look at:
Get all of the Classes in the Classpath and Get list of fields with annotation, by using reflection
2) Force your Properties class to be initialized in all possible enter points of your application. In static section in this class you will load your properties file, and then using (1) method with reflection and classloader, assign values to all constants.