Best practice for grouping Java classes for instantiation clarity - java

I am building a piece of software that sends and receives messages in particular binary definitions and with a particular version. As such, I have classes that look like this, which vary mostly only in the package name (the version, in this case):
For version 1.5:
com.mydomain.clothesmessage.v0105.fielddefinitions.Field100
com.mydomain.clothesmessage.v0105.fielddefinitions.Field200
com.mydomain.clothesmessage.v0105.messagedefinitions.Pants
com.mydomain.clothesmessage.v0105.messagedefinitions.Socks
and for version 2.7:
com.mydomain.clothesmessage.v0207.fielddefinitions.Field100
com.mydomain.clothesmessage.v0207.fielddefinitions.Field200
com.mydomain.clothesmessage.v0207.messagedefinitions.Pants
com.mydomain.clothesmessage.v0207.messagedefinitions.Socks
The class that manages the transmission and reception of these messages uses all versions, depending on where the message comes from, etc.
My problem is that defining an instance of the class requires I use the entire package path, because otherwise it's ambiguous. Even if there exists a situation where I use only one version in a given file, a casual reader of the code won't be able to see what version is being used. Pants pants = new Pants() is ambiguous until you look at the imported package.
My ideal usage of this would be something like this:
V0207.Pants pantsMessage = new V0702.Pants();
That makes it very clear what version is being used. I could make this happen by creating the Pants message classes as inner classes of the V0207 class, but then the V0207 class becomes gigantic (there could be a hundred messages, each with 100 fields, for every given version). Is there possibly a way to #include an inner class, so they can be stored in separate files? This would be ideal.
I suppose I can emulate this with a wrapper class, that does something (silly?) like this, where there exists an instance of the Pants class in the V0207 object:
Object pantsMessage = V0207.pants.getClass().newInstance();
((com.mydomain.clothesmessage.v0207.messagedefinitions.Pants)pantsMessage).getZipperType();
But I dislike that. It looks contrived and requires try/catch and casting when in use. Terrible.
I could also use a factory. That would be a bit nicer, but requires a parent class (or interface) and would require casting when used, since each message has unique methods.
Message pantsMessage = V0207Factory.newMessage(V0207.PantsMessage);
((com.mydomain.clothesmessage.v0207.messagedefinitions.Pants)pantsMessage).getZipperType();
or
Message sockMessage = V0207Factory.newSock();
((com.mydomain.clothesmessage.v0207.messagedefinitions.Socks)sockMessage).getSmellLevel();
What are your thoughts? I'm using JDK 1.7, but 1.8 might be usable.

Consider using the factory design pattern with interfaces. The version of Java that you use does not make a difference (though support for Java 7 goes away in the spring, April if I remember correctly).
Define an interface for each class containing the method signatures that will be implemented by all the versions of the class.
Update your class definitions to include the appropriate interface definition.
Create a class factory for each needed class, passing it the information needed to create the appropriate version of the class. This class factory should return the interface type for the created class.
Here is an example:
TestPants
public class TestPants {
IPants pants = PantsFactory.PantsFactory(207);
Message zipperType = pants.getZipperType();
Message color = pants.getColor();
)
}
IPants
public interface IPants {
Message getZipperType();
Message getColor();
}
Pants
public class Pants implements IPants {
// Class fields and Object fields
#Override
public Message getColor () {
return null;
}
#Override
public Message getZipperType () {
return null;
}
// implement any common methods among all versions
}
PantsV0105
public class PantsV0105 extends Pants {
// add changes for this version
}
PantsV0207
public class PantsV0207 extends Pants {
// add changes for this version
}
PantsFactory
public class PantsFactory {
public static IPants PantsFactory(int version) {
switch (version) {
case 105: return new PantsV0105(); break;
case 207: return new PantsV0207(); break;
default: return null;
}
}

I initially solved this by using inner static classes in one gigantic "version" class. Thus, the use looked like this:
V0207.Pants pantsMessage = new V0702.Pants();
But the version class ('V0207') grew too quickly, especially as other developers on the team demanded a more "Java" way of setting the fields (which required a lot of getters and setters).
Thus, the final solution is to put the messages inside their own v0207.messages package name, and prepend each message with the version:
V0207_Pants pantsMessage = new V0702_Pants();
It's not as nice as using a C++ namespace, but it works. The version is clear to the reader, and the object can contain a lot of code without any files becoming too large.

Related

How to check if a Java interface has an implementation? [duplicate]

Can I do it with reflection or something like that?
I have been searching for a while and there seems to be different approaches, here is a summary:
reflections library is pretty popular if u don't mind adding the dependency. It would look like this:
Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
ServiceLoader (as per erickson answer) and it would look like this:
ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class);
for (Pet implClass : loader) {
System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat
}
Note that for this to work you need to define Petas a ServiceProviderInterface (SPI) and declare its implementations. you do that by creating a file in resources/META-INF/services with the name examples.reflections.Pet and declare all implementations of Pet in it
examples.reflections.Dog
examples.reflections.Cat
package-level annotation. here is an example:
Package[] packages = Package.getPackages();
for (Package p : packages) {
MyPackageAnnotation annotation = p.getAnnotation(MyPackageAnnotation.class);
if (annotation != null) {
Class<?>[] implementations = annotation.implementationsOfPet();
for (Class<?> impl : implementations) {
System.out.println(impl.getSimpleName());
}
}
}
and the annotation definition:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PACKAGE)
public #interface MyPackageAnnotation {
Class<?>[] implementationsOfPet() default {};
}
and you must declare the package-level annotation in a file named package-info.java inside that package. here are sample contents:
#MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class})
package examples.reflections;
Note that only packages that are known to the ClassLoader at that time will be loaded by a call to Package.getPackages().
In addition, there are other approaches based on URLClassLoader that will always be limited to classes that have been already loaded, Unless you do a directory-based search.
What erickson said, but if you still want to do it then take a look at Reflections. From their page:
Using Reflections you can query your metadata for:
get all subtypes of some type
get all types annotated with some annotation
get all types annotated with some annotation, including annotation parameters matching
get all methods annotated with some
In general, it's expensive to do this. To use reflection, the class has to be loaded. If you want to load every class available on the classpath, that will take time and memory, and isn't recommended.
If you want to avoid this, you'd need to implement your own class file parser that operated more efficiently, instead of reflection. A byte code engineering library may help with this approach.
The Service Provider mechanism is the conventional means to enumerate implementations of a pluggable service, and has become more established with the introduction of Project Jigsaw (modules) in Java 9. Use the ServiceLoader in Java 6, or implement your own in earlier versions. I provided an example in another answer.
Spring has a pretty simple way to acheive this:
public interface ITask {
void doStuff();
}
#Component
public class MyTask implements ITask {
public void doStuff(){}
}
Then you can autowire a list of type ITask and Spring will populate it with all implementations:
#Service
public class TaskService {
#Autowired
private List<ITask> tasks;
}
The most robust mechanism for listing all classes that implement a given interface is currently ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author.)
try (ScanResult scanResult = new ClassGraph().whitelistPackages("x.y.z")
.enableClassInfo().scan()) {
for (ClassInfo ci : scanResult.getClassesImplementing("x.y.z.SomeInterface")) {
foundImplementingClass(ci); // Do something with the ClassInfo object
}
}
With ClassGraph it's pretty simple:
Groovy code to find implementations of my.package.MyInterface:
#Grab('io.github.classgraph:classgraph:4.6.18')
import io.github.classgraph.*
new ClassGraph().enableClassInfo().scan().withCloseable { scanResult ->
scanResult.getClassesImplementing('my.package.MyInterface').findAll{!it.abstract}*.name
}
What erikson said is best. Here's a related question and answer thread - http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html
The Apache BCEL library allows you to read classes without loading them. I believe it will be faster because you should be able to skip the verification step. The other problem with loading all classes using the classloader is that you will suffer a huge memory impact as well as inadvertently run any static code blocks which you probably do not want to do.
The Apache BCEL library link - http://jakarta.apache.org/bcel/
Yes, the first step is to identify "all" the classes that you cared about. If you already have this information, you can enumerate through each of them and use instanceof to validate the relationship. A related article is here: https://web.archive.org/web/20100226233915/www.javaworld.com/javaworld/javatips/jw-javatip113.html
Also, if you are writing an IDE plugin (where what you are trying to do is relatively common), then the IDE typically offers you more efficient ways to access the class hierarchy of the current state of the user code.
I ran into the same issue. My solution was to use reflection to examine all of the methods in an ObjectFactory class, eliminating those that were not createXXX() methods returning an instance of one of my bound POJOs. Each class so discovered is added to a Class[] array, which was then passed to the JAXBContext instantiation call. This performs well, needing only to load the ObjectFactory class, which was about to be needed anyway. I only need to maintain the ObjectFactory class, a task either performed by hand (in my case, because I started with POJOs and used schemagen), or can be generated as needed by xjc. Either way, it is performant, simple, and effective.
A new version of #kaybee99's answer, but now returning what the user asks: the implementations...
Spring has a pretty simple way to acheive this:
public interface ITask {
void doStuff();
default ITask getImplementation() {
return this;
}
}
#Component
public class MyTask implements ITask {
public void doStuff(){}
}
Then you can autowire a list of type ITask and Spring will populate it with all implementations:
#Service
public class TaskService {
#Autowired(required = false)
private List<ITask> tasks;
if ( tasks != null)
for (ITask<?> taskImpl: tasks) {
taskImpl.doStuff();
}
}

java declare anonymous class using proxy api

This morning I fell into a particular case that never happened to me before. I'm developing a Minecraft plugin using the minecraft server API which is usually called NMS with reference to the name of its packages (eg net.minecraft.server.v1_13_R1 for version 1.13).
The main problem with the use of the minecraft server API is that it is difficult to write a cross version code: indeed the name of the packages changes with each new version.
When the plugin only supports two versions it is usually easier to use the interfaces to write two different codes depending on the version. But when you have to support a dozen different versions (and this is my case), it's a bad idea (the plugin would be much too heavy, it would have to import every jar in the IDE, and I would have to redo the code with each new version).
In these cases I usually use reflection but I do not think it's possible here:
packet = packetConstructor.newInstance(
new MinecraftKey("q", "q") {
#Override
public String toString() {
return "FML|HS";
}
},
packetDataSerializerConstructor.newInstance(Unpooled.wrappedBuffer(data)));
As you probably guessed MinecraftKey is a class from NMS and I was told to use Java Dynamic Proxy API. I have never used it and would like to know if you would know a place that would explain to me how to do it simply? If you know of another better method that interests me too!
When I think about it, I think that this is really a lot of trouble for a tiny piece of code x)
EDIT :
My plugin uses the PacketPlayOutCustomPayload (aka plugin messages) to communicate with the mods of the players. It allows me to send a message (a byte []) on a particular channel (a String). But with the 1.13 this String has been replaced by a MinecraftKey (a wrapper for the String that replaces some characters and requires the use of a ":"). This poses a problem when players connect to 1.12 on my 1.13 server so I do not have a choice: I have to override the MinecraftKey object in this case.
I don’t really think using proxy classes is good solution here, it will only make it harder to debug, but if you need something like that you should use library like ByteBuddy: (as java can’t generate proxy for a class, only interfaces are allowed)
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.FixedValue;
import static net.bytebuddy.matcher.ElementMatchers.*;
public class Main {
public static void main(String[] args) throws Exception {
SomeKey someKey = new SomeKey("my", "key");
System.out.println(someKey); // :<
// this class should be cached/saved somewhere, do not create new one each time.
Class<? extends SomeKey> loaded = new ByteBuddy()
.subclass(SomeKey.class)
.method(named("toString").and(returns(String.class).and(takesArguments(0))))
.intercept(FixedValue.value("something"))
.make()
.load(Main.class.getClassLoader()).getLoaded();
someKey = loaded.getConstructor(String.class, String.class).newInstance("what", "ever");
System.out.println(someKey); // YeY
}
}
class SomeKey {
final String group;
final String name;
public SomeKey(String group, String name) {
this.group = group;
this.name = name;
}
public String getGroup() { return this.group; }
public String getName() { return this.name; }
#Override public String toString() {
return group+":"+name;
}
}
But I would just create separate modules in my project, one that does only work with real bukkit API and contains many interfaces to represent NMS types in some normalised and readable way.
And separate modules for each version, then you will not have much code to duplicate, as most of it will be abstracted and handled by that “core/base” module.
Then you can build it as one single fat jar or separate .jar per version.
Other solution might be using some template engines and preprocessors to generate java sources on build time, see how fastutil is doing this:
https://github.com/vigna/fastutil
And yet another solution for simple classes and parts of code would be to use build-in javascript or external script language like groovy to also create this pattern-line but in runtime. But I would use this only for simplest stuff.
Also for just using methods you can just use normal reflections.
You can also always inject into netty and instead of using default packet serializer just write own bytes, then you don't need that key at all.

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.

Alias Classes in Java

I have a series of auto generated classes that result in the same class name. The solution to this was to separate the classes into different packages. When creating functions in another class that uses multiple auto generated classes my code results in something like the following to avoid class and package collision issues.
... Other methods with similar functionality that reference a
different auto generated class.
//////////////////////////////////////////////////////////////////////////////
public FutureTask<com.CompanyName.ProductName.SDK.Device.
GetCommandsResponse.ObjectClass> SendLogEntryEventAsync(final
com.CompanyName.ProductName.SDK.Device.GetCommandsRequest
request)
{
FutureTask<com.CompanyName.ProductName.SDK.Device.GetCommandsResponse.
ObjectClass> futureTask;
Callable<com.CompanyName.ProductName.SDK.Device.GetCommandsResponse.
ObjectClass> call = new Callable<com.CompanyName.ProductName.SDK.Device.
GetCommandsResponse.ObjectClass>()
{
public com.CompanyName.ProductName.SDK.Device.GetCommandsResponse.
ObjectClass call() throws ResponseException
{
return SendGetCommandRequest(request);
}
};
futureTask = new FutureTask<com.CompanyName.ProductName.SDK.Device.
GetCommandsResponse.ObjectClass>(call);
return futureTask;
}
////////////////////////////////////////////////////////////////////////
... More methods with similar functionality that reference a
different auto generated class.
///////////////////////////////////////////////////////////////////////////////
This is not a problem for me as a programmer, as I don't mind typing out the packages when casting or declaring types.
What concerns me is, that because this code is intended to be part of an SDK and will be distributed to third party developers, these long class names will become irritating; and at worst developers will refuse to use the SDK due to hassle.
Is it possible to create wrapper classes that alias these auto-generated classes, so the names are unique, easy to understand, caste, and declare?
If so how would I do this?

Simple Java "Service Provider frameworks"?

I refer to "service provider framework" as discussed in Chapter 2 of Effective Java, which seems like exactly the right way to handle a problem I am having, where I need to instantiate one of several classes at runtime, based on a String to select which service, and an Configuration object (essentially an XML snippet):
But how do I get the individual service providers (e.g. a bunch of default providers + some custom providers) to register themselves?
interface FooAlgorithm
{
/* methods particular to this class of algorithms */
}
interface FooAlgorithmProvider
{
public FooAlgorithm getAlgorithm(Configuration c);
}
class FooAlgorithmRegistry
{
private FooAlgorithmRegistry() {}
static private final Map<String, FooAlgorithmProvider> directory =
new HashMap<String, FooAlgorithmProvider>();
static public FooAlgorithmProvider getProvider(String name)
{
return directory.get(serviceName);
}
static public boolean registerProvider(String name,
FooAlgorithmProvider provider)
{
if (directory.containsKey(name))
return false;
directory.put(name, provider);
return true;
}
}
e.g. if I write custom classes MyFooAlgorithm and MyFooAlgorithmProvider to implement FooAlgorithm, and I distribute them in a jar, is there any way to get registerProvider to be called automatically, or will my client programs that use the algorithm have to explicitly call FooAlgorithmRegistry.registerProvider() for each class they want to use?
I think you need to create a META-INF/services/fully.qualified.ClassName and list things there, but I don't remember the spec (JAR File Specification or this).
The Practical API design confessions of a Java architect book chapter 8 is about SPI.
The ServiceLoader might help you to list available implementations. For example with the PersistenceProvider interface:
ServiceLoader<PersistenceProvider> loader =
ServiceLoader.load(PersistenceProvider.class);
Iterator<PersistenceProvider> implementations = loader.iterator();
while(implementations.hasNext()) {
PersistenceProvider implementation = implementations.next();
logger.info("PersistenceProvider implementation: " + implementation);
}
You could have the client JAR register the providers in a static initializer block within some class that you know will be called before FooAlgorithmRegistry.getProvider(), something like:
static {
FooAlgorithmRegistry.registerProvider("test", new MyFooAlgorithmProvider());
}
But, it might be pretty hard to find a way to guarantee that this will run (static initializers are guaranteed to be run once and only once, when the class is first loaded) before the accessor method of the factory.

Categories