respecting the DRY principle for variable containing the class name - java

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);

Related

Java: make static methods of one class mirror instance methods of another class

I have a POJO like this:
public class Foo {
private String bar1;
private String bar2;
//...
public String getBar1() { return bar1; }
public void setBar1(String bar1) { this.bar1 = bar1; }
public String getBar2() { return bar2; }
public void setBar2(String bar2) { this.bar2 = bar2; }
//...
}
As an alternative to Java reflection (which is quite slow in general), I would like to define a class with static methods like this:
public class FooStatic {
public static String getBar1(Foo foo) { return foo.getBar1(); }
public static void setBar1(Foo foo, String bar1) { foo.setBar1(bar1); }
public static String getBar2(Foo foo) { return foo.getBar2(); }
public static void setBar2(Foo foo, String bar2) { foo.setBar2(bar2); }
//...
}
which enforces the creation/deprecation of a static method every time the Foo class is updated. For example, if the field bar2 is deleted in FooStatic, then the static methods getBar2() and setBar2() in FooStatic should be identified by the compiler to be removed. If a new variable bar3 is added to Foo with getters and setters, the compiler should enforce the creation of new static methods getBar3() and setBar3() in FooStatic. Moreover, I have multiple POJOs, and would like a solution which scales. Is this possible?
Yes... sort of. It's very complicated.
Annotation Processors are compiler plugins that run at certain times during the compilation process. It gets complex fast - IDEs and build tools are 'incremental' (they don't want to recompile your entire code base everytime you change a single character, of course), for example.
Annotation processors can do a few things:
They can run as part of the compilation processes. This can be done automatically - they just need to be on the classpath, is all
They can be triggered due to the presence of an annotation.
They can read the signatures of existing files (the names of fields and methods, the parameter names, parameter types, return type, and throws clause, and the type of fields, and the extends and implements clauses, and the param names and types of the constructors). They can't read the body content (initializing expressions, method and constructor bodies). But I think you just need the signatures here.
They can make new files. They can even make new java files which will then automatically get compiled along with the rest.
Thus, you have a route here: Make an annotation, then make an annotation processor. For example, you could set it up so that you manually write:
#com.foo.Hossmeister.Singletonify
class Example {
void foo1() {}
String foo2(String arg) throws IOException {}
}
and have an Annotation Processor (which also has that com.foo.Hossmeister.Singletonify annotation), which, if it is on the classpath, automatically generates and ensures that all other code can automatically see this file:
// Generated
class ExampleSingleton {
private ExampleSingleton() {}
private static final Example INSTANCE = new Example();
public void foo1() {
INSTANCE.foo1();
}
public static String foo2(String arg) throws IOException {
return INSTANCE.foo2(arg);
}
}
But, annotation processors are tricky beasts to write, and they can be quite a drag on the compilation process. Still, that's the only way to get what you want. Now you have something to search the web for / read up on :)
You start by making a separate project that defines the annotation, has the annotation processor (a class that extends AbstractProcessor), pack that into a jar, and make sure the manifest includes an SPI file that tells java that your class that extends AbstractProcessor is an annotation processor, and then it'll be picked up automatically. I'll give you the annotation definition:
In a file named Singletonify.java:
#Retention(RetentionPolicy.CLASS)
#Target(ElementType.TYPE)
public #interface Singletonify {}
But... wait!
The concept of singletons is often problematic. Singletons should be 'stateless' - and if they are stateless, why isn't your Foo class just filled with entirely static methods, obviating the need for your "static mirror class"? If it is stateful, you now have global state which is a virtually universally decried anti-pattern. You don't want global state, it makes reasoning about control flow impossible.
A second problem is testability - because static stuff doesn't 'do' inheritance, you can't (easily) make test implementations of static methods. With non-static stuff this is much easier.
This problem is more generally solved by so-called Dependency Injection frameworks such as Dagger, Guice, or Spring. They let you write code that just 'gets' an instance of your Foo class, without callers having to actually figure out where to get this instance from: The Dependency Injection framework takes care of it. It lets you do things like "Have a singleton of this object... per web session". Which is pretty powerful stuff.
I think what you probably want is a DI system. You may want to investigate a bit before spending the 2 weeks writing that annotation processor.

Recommended way to generate a java file from another java file

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.

How to append a method to existing class using annotation processing in java / kotlin?

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.

Injecting Constants via Custom Annotation

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.

final static String defined in an interface not evaluated at compile time - Android

I have two classes and an interface (for example DatabaseModel, LocalStore, and InternalModelInterface). They're defined as follows;
public class DatabaseModel {
// ...
public static final String KEY_PARAM1 = "param1";
}
public class LocalStore implements InternalModelInterface {
// ...
public void function () {
String temp = InternalModelInterface.COLUMN_PARAM1;
}
}
public interface InternalModelInterface {
public static final String COLUMN_PARAM1 = DatabaseModel.KEY_PARAM1;
// ...
}
The issue I'm experiencing is that at runtime, when I call localStore.function(), temp is being assigned null, as InternalModelInterface.COLUMN_PARAM1 is null. Does this make sense? Shouldn't InternalModelInterface.COLUMN_PARAM1 be evaluated at compile time and inlined?
This is for an Android application. Thanks in advance.
I'll further explain to clarify any confusion.
Objects of the DatabaseModel class are instantiated as a JSON response is parsed. The constants defined in the DatabaseModel class represent the keys to look for in the JSON response.
The InternalModelInterface defines the column names used in the local (cache) database on the device. For several reasons (including they keys being illegal column names in SQLite), I'm not reusing the keys as column names.
The reason I'm using an interface and not just a plain class is that the interface also specifies required methods that need to be implemented by the third class, LocalStore.
JLS3 §8.3.2.1, §9.3.1 http://java.sun.com/docs/books/jls/third_edition/html/classes.html#38010
at run time, static variables that are
final and that are initialized with
compile-time constant values are
initialized first. This also applies
to such fields in interfaces (§9.3.1).
These variables are "constants" that
will never be observed to have their
default initial values (§4.12.5), even
by devious programs.
So null should never be observed in your example. It's an Android bug then.
I'm not and android expert but I think that if you don't create an instance of the class, it's optimised out at compile time. If you create a constructor for DatabaseModel and instantiate it somewhere it seems to solve this for me.

Categories

Resources