How to create protobuf instances using java reflection? - java

Normally you create an protobuf class instance like this:
Bar.Builder bld = Bar.newBuilder();
bld.setXYZ(...
I have a usecase that uses the Java reflection to instantiate a protobuf class:
Class clsBar = Class.forName("com.xyz.Foo$Bar");
Object instance = clsBar.newInstance(); // error here!
Method mth = clsBar.getMethod(...);
The above code works fine with normal Java classes. But for a generated protobuf class "com.xyz.Foo$Bar", It gives me an NoSuchMethodException, as there isn't a default public constructor there.
Any suggestions on how to use Java refection to create protobuf instances? The question is for someone who's really good at protobuf internals. Thank!

I think you should go the full way: through the Builder class:
//get Bar class
Class barClass = Class.forName("com.xyz.Foo$Bar");
//instantiate Builder through newBuilder method
Method newBuilderMethod = barClass.getMethod("newBuilder");
Bar.Builder builder = (Bar.Builder) newBuilderMethod.invoke(null);
// ... set properties -- can be through reflection if necessary
//build:
Bar bar = builder.build();
Though I don't exactly see how reflection is of any use in this case, that would probably require a deeper understanding of the exact problem you are trying to solve.

Related

How to pass PHP class as parameter to a builder function?

I implemented an object builder which takes a class name and tries to create a new instance object. The builder tries to inject services if any required. The class name is passed as a string in the current implementation. Here is an example
$className = '\Example\Application\ServiceClass';
$service = CiContext::newInstance($className);
However, this is not compatible with my IDE (eclipse) and the refactoring process does not find the class name (in the string form).
Is there any way to get the class name like java does?
Class classInstance = ServerClass.class;
In this case, the refactoring process finds the class reference and changes the class name.
Well, PHP7 class constant is supported on a class name. For example, the following code is correct in PHP 7.4:
$service = CiContext::newInstance(\Example\Application\ServiceClass::class);
This will solve my problem and the IDE find the class usage.
On the other hand, the class literal is going to support for objects too. For more information see class literal on object

wither vs builder Lombok library

I have started using the Lombok library, and I am unable to figure out the difference between using a wither & a builder.
#Builder
#Wither
public class Sample {
private int x;
private int y;
}
Now I can create an object in 2 ways:
Sample s = new Sample().builder()
.x(10)
.y(15)
.build();
OR
Sample s = new Sample()
.withx(10)
.withy(10);
What is the difference between the two? Which one should I use?
#Builder is used to create mutable objects, #Wither for immutables.
Disclosure: I am a lombok developer.
Generally, the difference is when you build a object with builder(), you must call build() method at last, and before you call build(), all property values are saved in the internal builder object instead of the object your created with new. After you setted all properties and call build(), a new object will be created. See details here: https://projectlombok.org/features/Builder.html . I think the better way for builder pattern is:
Sample s = Sample.builder()
.x(10)
.y(15)
.build();
Because the first Sample object is redundant.
For withers, every time you called withXXX(xxx), a new object is returned, with XXX set to xxx, and all other properties cloned from the object you called wither on (if xxx is different from the original xxx. See details here: https://projectlombok.org/features/experimental/Wither.html). Choose which way, I think it's only depends on your personal habit and your project's code style.
Hope this could help you.

Design Patterns, override a method without need to re compile / relink

We are building a product that needs to run on production environments. We need to modify some of the functionality of a existing library. The existing library has class's and methods, we need to override 1 or more methods so that the caller uses our overriden methods instead of the original library.
OriginalLibrary
package com.original.library ;
public class OriginalLibrary {
public int getValue() {
return 1 ;
}
public int getAnotherValue() {
return 1 ;
}
}
Original Client
public class MyClient {
private OriginalLibraryClass originalLibraryObject ;
public MyClient () {
originalLibraryObject = new OriginalLibraryClass() ;
System.out.println(originalLibraryObject.getValue()) ;
System.out.println(originalLibraryObject.getAnotherValue()) ;
}
}
Output
1
2
Now, I need to change getValue() to return 3, instead of 1
Needed Output
3
2
package com.original.library.improved ;
public class OriginalLibrary extends com.original.library.OriginalLibrary {
public int getValue() {
return 3 ;
}
public int getAnotherValue() {
return super.getAnotherValue() ;
}
}
If I do the above, I need to tell my Original Client to reorder and use my new com.original.library.improved jar file before com.original.library.
I am almost convinced that this is the most non intrusive way to launch my improved services over and above the OriginalLibrary. I would have preferred a solution where I need to tell the customer to just add my jar file, no need to recompile, relink your client code.
Similar (not same) questions on a google search
here
here
java assist is excellent library for bytecode manipulation. I have modified code below as per your sample code given, You have to explore javaassist more for your actual requirenment
CtClass etype = ClassPool.getDefault().get("com.original.library.OriginalLibrary");
// get method from class
CtMethod cm = etype.getDeclaredMethod("getValue");
// change the method bosy
cm.setBody("return 3;");
etype.rebuildClassFile();
// give the path where classes is placed, In my eclipse it is bin
etype.writeFile("bin");
OriginalLibrary originalLibraryObject;
originalLibraryObject = new OriginalLibrary();
System.out.println(originalLibraryObject.getValue());
System.out.println(originalLibraryObject.getAnotherValue());
Now output of getValue is 3 because I changed body of that method.
A couple of questions -
How is the client getting an instance of your library's class?
If they are using new OriginalLibrary(), then you're pretty much stuck with creating a new subclass of OriginalLibrary and then asking your client to use your new OriginalLibraryImproved class. This is a common problem encountered in projects and is one reason why a library should not allow its clients to instantiate its classes directly using the new operator.
If instead, your client is instantiating OriginalLibrary using a factory method provided by the library (say, OriginalLibrary.getInstance()), you may want to check if there are any hooks into the factory that allow you to change the object being returned.
Do you have full control of the source code of the original library?
If yes, then you definitely should (and I cannot emphasize this strongly enough) provide factory methods for any class in the library that is instantiable. Doing this allows you to change the actual object being returned without modifying the client (as long as the returned object's class is a subclass of the return value from the factory method).
If not, then I suggest you do the following.
Create a subclass of OriginalLibrary (say, OriginalLibraryImproved).
Create a Factory class named OriginalLibraryFactory that has a static method named getInstance(). Write code to return an instance of OriginalLibraryImproved from this method.
Ask your client to replace all occurrences of new OriginalLibrary() with OriginalLibraryFactory.getInstance(). Note that this approach will only involve adding an extra import for the factory class. The client will still refer to the returned instance using the same OriginalLibrary reference as before.
The advantage of this approach is that it gives you complete flexibility to change the implementation details of OriginalLibraryImproved without affecting the client in anyway. You could also swap OriginalLibararyImproved with a newer version like OriginalLibraryImprovedVer2 and the client will be oblivious to the fact that it is using a new class. You'll just have to make sure that OriginalLibraryImprovedVer2 subclasses OriginalLibrary.
An even more flexible approach is to use the Wrapper or Decorator pattern to avoid the pitfalls of inheritance. You can understand more about the Decorator pattern here.
In a nutshell, try to avoid forcing your clients to use new and try to avoid inheritance unless you have very compelling reasons.

Is runtime-compiled-class instantiation & usage possible in Java without reflection?

I would like to know if there exists any kind of library or workaround to use my runtime compiled classes ( I dynamically generate my classes, writing .java, then compiling them in .class all of this happens at runtime) without using a reflection library?
Loading using reflection I always have to work like this:
//path where my newly generated classes are
File file = new File("e:\\tmp");
// Convert File to a URL
URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass("eu.dataaccess.footballpool.TGoal");
// Create an instance of the class just loaded
Object o = cls.newInstance();
Method method2 = cls.getDeclaredMethod("getIMinute");
Object result2 = method2.invoke(o);
My question is if it's somehow possible to use at runtime
TGoal x = new TGoal();
and
x.getIMinute();
EDIT: It seems it is impossible to act the way I hoped to. I modify my question so: is it possible to load a whole package at runtime, in a way that the classes of the loaded package are able to communicate each other without the method.invoke, meanwhile the main activation of the package is done with the method invoke() ?
I tried without any luck, i have some "error: cannot find symbol", it seems the runtime-loaded classes can't communicate each other
If you're not using the reflection api you have to instantiate classes via the new operator. This requires having the class file at compile time. So it is not possible. If your class TGoal is implementing an Interface IGoal, then you can cast your Object o to IGoal. This enables you to work with your Object like with any other object without using the reflection api.
You can do
x.getIMinute();
by using interfaces, but AFAIK you cannot create new class instances without reflection.
Instead, to call methods of your dynamically created objects, you
can declare an interface:
public interface MinuteGetter{
public int getIMinute();
}
Your dynamic objects have to implement his, than you can do:
Class cls = cl.loadClass("eu.dataaccess.footballpool.TGoal");
// Create an instance of the class just loaded
MinuteGetter o = (MinuteGetter) cls.newInstance();
o.getIMinute();
If applying an interface to your code is not an option for you, you can try to give a try to AnonymousClassLoader. See this detailed post about it.
It work only on Java 7, and please note that I never used it, so how don't know if it offer better performance than reflection.
Are you sure you have to create the Code at runtime? The easiest way is to avoid this.
If the TGoal x = new TGoal() doesn't have to happen in this program, then create a main function in the generated code and start a second java application.

Converting Java code thats calls iTunes DLLs from using Com4j to Jacob

I currently use Com4j to talk to iTunes from my Java app, unfortunately it does not work with 64bit Java and looks like it never will, so Im trying to use an alternative called Jacob instead.
Both libraries provide a tool to generate Java classes from a DLL, and the resultant classes are very similar and its been straightforward to change most of the code but Im failing on how to find subtypes
IITPlaylist object = itunes.createFolder(TextLabel.SAVE_ITUNES_PLAYLIST_FOLDER.getMsg());
IITUserPlaylist playlistFolder = object.queryInterface(IITUserPlaylist.class);
Both libraries have created IITPlaylist and IITUSerPlaylist classes but only com4j provides the queryInterface class, and no IITUserPlaylist is not actually a subclass of IITPlaylist.
Also com4j provides an is method, but jacob does not
if (next.is(IITFileOrCDTrack.class))
Anyone know how to resolve these issues ?
EDIT:
Made some progress but still not got it working, there is a QueryInterface method that takes the guid of the class (include the curly brackets) , I found the guid by looking at the jacobgenlog.txt file which is created when you run jacobgen on the iTunes executable
This then returns another Dispatch object that is meant to relate to the subclass, however the simple cast Ive done is invalid, whats the mising step ?
private static final String USER_PLAYLIST_GUID = "{0A504DED-A0B5-465A-8A94-50E20D7DF692}";
IITPlaylist object = itunes.createFolder(TextLabel.SAVE_ITUNES_PLAYLIST_FOLDER.getMsg());
IITUserPlaylist playlistFolder = (IITUserPlaylist)object.QueryInterface(USER_PLAYLIST_GUID);
The is() functionality is replaced by checking the kind
IITTrack next = tracks.getItem(i);
if(next.getKind().equals(ITTrackKind.ITTrackKindFile))
A spanner in the works is that jacobgen getKind() methods are invalid Java because they try to return a new interface, and of course you cannot instantiate an interface, so I had to modify them as follows
ITPlayListKind goes from
public interface ITPlaylistKind extends __MIDL___MIDL_itf_iTunesCOMInterface_0001_0081_0001 {
}
to
public enum ITPlaylistKind {
ITPlaylistKindUnknown,
ITPlaylistKindLibrary,
ITPlaylistKindUser,
ITPlaylistKindCD,
ITPlaylistKindDevice,
ITPlaylistKindRadioTuner;
}
Within IITUserPlaylist
public ITPlaylistKind getKind() {
return new ITPlaylistKind(Dispatch.get(this, "Kind").toDispatch());
}
to
public ITPlaylistKind getKind() {
return ITPlaylistKind.values()[Dispatch.get(this, "Kind").getInt()];
}
this wasnt an original idea by me, I got the idea from http://dot-totally.co.uk/software/itunescon/ which appears to be a modified version of the iTunes classes created by jacobgen, I didnt find it added that much and decided to stick with the jacobgen generated classes.
As soon as I set a bounty I work out the answer for myself.
Simply just use the constructor
IITPlaylist object = itunes.createFolder
(TextLabel.SAVE_ITUNES_PLAYLIST_FOLDER.getMsg());
IITUserPlaylist playlistFolder = new IITUserPlayList(object);
The QueryInterface and GUID sctrings re not required.
I was also having a problem working out how to add a track to a playlist, but you just need to
construct a Variant from the track ( I dont have to do this anywhere else)
IITTrack next = itunes.getLibraryPlaylist().getTracks()
.getItemByPersistentID(persistentId.getHighBit(),
persistentId.getLowBit());
playlist.addTrack(new Variant(nextTrack));

Categories