Instantiate a Java object through reflection - java

I have a question regarding a specific way of instantiating a Java object.
Basically, I need to implement a Singleton which implements an interface. I currently try to use a factory and a bit of reflection to do this, trying to reproduce this example (5th post, precisely).
The part that I like is that through this method, I can change the Singleton's implementation quite easily.
The problem is that I don't really understand how to retrieve the Class name. In the example above, the System.getProperty() seems to be a way to do this, but the example doesn't show precisely all the types needed to do this (the field isn't typed). The problem is that I don't know which key to give to the getProperty() method. It seems that it must be the singleton private static field's name with .type (i.e. mySingleton.name), but it doesn't seem to work...
I would like to know how can I retrieve the class name.
By the way, if there's a better way to do this, I'm open to suggestions.

typeName is String . So what you need is Fully Qualified Class Name to load the class with reflection like you
Class type = Class.forName(typeName);
System.getProperty() is a way to access the system properties/ environment properties that you have at the time of executing the program.
To narrow it down for you with an example you can set the system varible like below :
If in windows :
cmd> set a.type = mytest.testclass
If in linux :
$ export a.type = mytest.testclass
Make your the class that you are try to load is in classpath.
The above steps you need to perform before running your program.
Coming to best practices, the above approach can be used to test programs but when going into real time solutions you probably will have some way to read these class name from a file or database. Probably some kind of configuration parameter.

If you are asking about String typeName = System.getProperty("a.type"); in"
private synchronized static final void createA()
{
// This is just one possibility for getting the class name.
String typeName = System.getProperty("a.type");
Class type = Class.forName(typeName);
a = type.newInstance();
}
Where does a.type come from? - it's just System property, declared in your Operating system for this purpose only.
Class c = Class.forName("java.lang.String");
as shown above - Class.forName() requires fully qualified name of class - with package declaration

You can make the property anything you want. You can get the properties with System.getProperty("my.property") and you can turn this into a class with Class.forName()
Perhaps you could say what didn't work for you as its all pretty simple and I assume you are doing almost the right thing.

Related

Initialize (load) a java class with a java.lang.Class<T> instance

I have to admit that this is more a cosmetic issue, but the fact that I haven't found a more straight-forward solution makes me think I am probably missing something.
The thing is, my class (let's say Foo) has a very important static block where it registers itself (Foo.class) with a builder method in a Map, like this:
// somewhere in the class
static {
Bar.registerBuilder(Foo.class, Foo::build);
}
This makes it possibe to get a Foo builder from the Bar class, a bit like this:
// somewhere in a method
Foo foo = Bar.getBuilder(Foo.class).apply("Hello World");
(if the builder takes a String argument). However, the upper code example will only work if the Foo class was already initialized. If not, this means the static block of Foo wasn't executed and the builder isn't registered in Bar by now, which is leading to getBuilder() returning null and apply() throwing a NullPointerException.
Thanks to the internet (mostly StackOverflow) I found out that you can imperatively with Class.forName(String). But what really confuses me is that this method takes a String (therefore throws the checked ClassNotFoundException) and I haven't found a way to load and initialize a class directly via a java.lang.Class instance. I would have expected something like
Class<Foo> clazz = Foo.class;
clazz.load(); // does not exist
Instead I have to do this:
Class<Foo> clazz = Foo.class;
try {
Class.forName(clazz.getName());
} catch (ClassNotFoundException) {
// handle an exception that is actually unreachable
}
I would like to know if I am completely missing something, or if not, if there is a cleaner way to load and initialize a class via the java.lang.Class representation.
Any help is appreciated, thank you!
EDIT 1: As #Boris the Spider pointed out in the comments, Foo.class should probably already load and initialize the class, but it doesn't (in my case, at least) and that's why I even encountered this problem.
EDIT 2: Using the "complicated" way to load the class via Class.forName() (as in the code example) actually resolves the problem as I thought. It's just that I'd like to use a cleaner way if possible.
Using:
Java 11 (openjdk 11.0.2)
IntelliJ IDEA Ultimate (2019.3)
Maven (3.6.3)
If you are already referencing the class it would be much better to move that static code into normal static factory method. As why would you use reflections or try to reference some class just to make some code run when you can just run that method?
public static BuilderFunction createBuilder() {
return Foo::build;
}
And just call it in static block of Bar:
registerBuilder(Foo.class, Foo.createBuilder());
If you need something more dynamic you can use service loaders, especially with java 9+ as they are much nicer now to use:
provides my.BuilderProvder with something.FooProvider;
And just load them all in Bar:
ServiceLoader<BuilderProvder> loader = ServiceLoader.load(BuilderProvder.class);
loader.stream()
.forEach(provider -> registerBuilder(provider));
now even different modules not developed by you can provide own builders and you don't need to do any manual class loading (and class initialization is only guaranteed to happen if class is actually used, like some method or field used - note that constants are inlined at compilation so they don't count).
You can also use some hacky reflection libraries like ClassGraph or Reflections to get all classes of given type/with given annotation and then load them and invoke some init method on them all just like in my first proposed solution with createBuilder. This is how many components inside spring are registered, similar thing can be done with java annotation preprocessing to find this classes at compile time and just save the names. But if possible I would suggest sticking to existing build in solutions like service loaders.

How to solve this requirement, Android conditional serializedName

Am trying to increase security to my request payload, one of the measures is encrypting or blurring the member key of my json this way it's more ambiguous...
Here is what am trying to do,
public class LoginRequest {
private static final String SERIALIZED_NO = BuildConfig.DEBUG ? "no": "xyz";
private LoginRequest() {
// This class is not publicly instantiable
}
public static class ServerLoginRequest extends ParentRequest {
#Expose
#SerializedName(SERIALIZED_NO)
private String no;
Here is an image of my code...
Now the error is that this, #SerializedName(SERIALIZED_NO) must be a constant
i read some articles but no luck so far i think there is no way of conditional annotation like in C#, btw, of course, i can handle this with my back end since its not java, in some smart way.
This looks like a duplicate of How to supply value to an annotation from a Constant java to me however there is solution but I don't think you'l like it :)
Here is what you can do:
Create two new source code hierarchies, one starting with debug and the other starting with release - at the same level as your main hierarchy.
Place one copy of your model under debug/java/...your package structure to model..., with #SerializedName("no")
Place another copy of your model under release/java/...your package structure to model..., with #SerializedName("xyz")
Remove your data model from main/...your package structure to model... hierarchy
You will now be able to use your model under main but it will always be one or another, depending on build type you are using.
SERIALIZED_NO is obviously not constant. Its value is dependent to BuildConfig.DEBUG. It sounds however a bit unnecessary to use a constant as condition to make another constant which won't be a constant anymore. Try to move definition of SERIALIZED_NO to interface and see what happens otherwise you can use Dependency Injection that is equivalent to compiler directives in C++.

Modify library class at runtime - java/maven

I'm working on a Maven Plugin and I need to modify one class of an external jar (used during maven execution), to add:
a new field on this class
a getter for the field
some behavior to an existing setter to populate the field
The library code should use my 'new' class, and I want to be able to use the getter to retrieve some additional information.
Instances of this class are created within the library code (I'm not creating them in my code, I just need to access them).
Class is a non-final public class.
Do you know if this feasible and which is the best way to do it? Is it possible to do it with ByteBuddy?
EDIT: I cannot wrap the class, because it's not instantiated in my own code, let me elaborate a bit.
There's a library class named "Parser" that instantiate and populate some "Element" instances. My code looks like:
List<library.Element> elements = new library.Parser(file).parse();
the Parser.parse() method calls "Element.setProperties(List properties)" on each element.
I want to be able to enrich the setProperties method to store the original list of properties (that are lost otherwise)
Thanks
Giulio
At the end I managed to obtain the wanted result with byte-buddy (I don't know if it's the best solution but it works):
instrument library class (library.Element) using 'rebase' strategy to delegate the method 'setProperties' call to an interceptor.
Note: this must be done as the first instruction of the maven plugin execution when library.Element.class is not yet loaded (I didn't want to use a JVM agent)
define the above interceptor as a class that stores the original 'properties' value in a global map (key = identity hash code of the object, value = properties) and then call the original 'setProperties' method of library.Element
change my code to get properties from the map, instead of library.Element getter (I had already a wrapper of this class).
If someone is interested, I can show some code.
Your suggestion sounds a bit hackish, and in general what you want to do would not even be possible without generating sources from the JAR, modifying them, and then repackaging. If I faced this problem, I would consider using a decorator pattern instead. You can create a wrapper which exposes all the methods of your JAR, except it would add one extra field along with a getter and setter.
import com.giulio.old.jar.everything.*;
public class WrapperOfJar {
private String newField;
public String getNewField() { // ... }
public void setNewField() { // ... }
// all getters and setters from current JAR
}
Now your users will see the same interface, plus one new method for your field. This answer assumes that the class in question is not final.

When are dot operators required?

When calling a method, I get that you have to use instanceName.method() or className.method(). However, in some cases the instanceName or className is omitted in the code and just method() is written.
Programming language is Java. Just covering this for the AP Computer Science test and I have relatively limited knowledge of coding outside of the parameters of the course so a easy to understand explanation would be greatly appreciated.
My book says something about client programs but I'm not exactly sure what it means (both in general and about client programs specifically).
I'll put my explanation as simply as possible - Usually you would use instanceName.method() when trying to effect the variables within a class. For example a "Cat" object, you could make a cat - Cat catOne = new Cat() and then use its methods catOne.setName("Kitty");. This will set this objects name to "Kitty", leaving all other cat objects with the ability to have their own unique name.
Using className.method() is done when using a static method within a class, eg public static int method(), and then using it in another class. This does not require you to instantiate an object for that class, and can use them willingly. For example, having a class called MathConstants and using something like MathConstants.getPi() ( Sorry for the crude example ).
When methods are called like methodName() , this means that the method is located within the class itself. Usually we use this , as in this.methodName(), but just using methodName() is okay.
Hope that is easy to understand

Can reflection bind a class to a new name?

I am trying to let users of my program rename classes and methods in the class. The new names can be read in and configured at run time and they will call these classes and methods in a scripting language using Java Script Engine. I need a way to bind their new names to the real names of the classes and methods. I have been looking at Reflection but I do not think this can provide me with the capability I need, or is this even possible?
Ex:
public class RealName {
public void printHello() {
System.out.println("Hello");
}
}
Then in maybe Paython say
obj = new NewName()
obj.hello()
Tell me if this is impossible please!
You can not change the method names, but you can bind an instance of an object to a given name and inject that into the context of the scripting language.
This would only work for that instance of the class, not for instantiating new instances.
If you really want this you may be able to generate sub classes with the new name and method names in the target scripting language and inject them into to the context to get the effect you are looking for.
Having said all that I can't really come up with a good reason to do any of this.
To answer my question from what I've found no you cannot use reflection to bind a class to a new name. In fact I found no easy way to do dynamic renaming.
What I did to overcome this was to write code from a string to a file, save that file with extension .java, compile that file, then use it with reflection or better yet use it inside a script using the Java ScriptEngine API (that way you can avoid the ugly reflection code and actually have everything dynamic and on the fly).
Here's a starting point for creating the file,
Dynamic in-memory compilation
And here's something for scripting Java,
Scripting for Java

Categories

Resources