Introduction
As a disclaimer, I'v read Why can't static methods be abstract in Java and, even if I respectfully disagree with the accepted answer about a "logical contradiction", I don't want any answer about the usefulness of static abstract just an answer to my question ;)
I have a class hierarchy representing some tables from a database. Each class inherits the Entity class which contains a lot of utility methods for accessing the database, creating queries, escaping characters, etc.
Each instance of a class is a row from the database.
The problem
Now, in order to factorize as much code as possible, I want to add information about related columns and table name for each class. These informations must be accessible without a class instance and will be used in Entity to build queries among other things.
The obvious way to store these data are static fields returned by static methods in each class. Problem is you can't force the class to implement these static methods and you can't do dynamic linking on static methods call in Java.
My Solutions
Use a HashMap, or any similar data structure, to hold the informations. Problem : if informations are missing error will be at runtime not compile time.
Use a parallel class hierarchy for the utility function where each corresponding class can be instantiated and dynamic linking used. Problem : code heavy, runtime error if the class don't exist
The question
How will you cope with the absence of abstract static and dynamic linking on abstract method ?
In a perfect world, the given solution should generate a compile error if the informations for a class are missing and data should be easily accessible from withing the Entity class.
The answer doesn't need to be in Java, C# is also ok and any insight on how to do this without some specific code in any language will be welcomed.
Just to be clear, I don't have any requirement at all besides simplicity. Nothing have to be static. I only want to retrieve table and columns name from Entity to build a query.
Some code
class Entity {
public static function afunction(Class clazz) { // this parameter is an option
// here I need to have access to table name of any children of Entity
}
}
class A extends Entity {
static String table = "a";
}
class B extends Entity {
static String table = "b";
}
You should use the Java annotation coupled with the javac annotation processor, as it's the most efficient solution. It's however a bit more complicated than the usual annotation paradigm.
This link shows you how you can implement an annotation processor that will be used at the compile time.
If I reuse your example, I'd go this way:
#Target(ElementType.TYPE)
#Retention(RetentionType.SOURCE)
#interface MetaData {
String table();
}
abstract class Entity {}
#MetaData(table="a")
class A extends Entity {}
#MetaData(table="b")
class B extends Entity {}
class EntityGetter {
public <E extends Entity> E getEntity(Class<E> type) {
MetaData metaData = type.getAnnotation(MetaData.class);
if (metaData == null) {
throw new Error("Should have been compiled with the preprocessor.");
// Yes, do throw an Error. It's a compile-time error, not a simple exceptional condition.
}
String table = metaData.table();
// do whatever you need.
}
}
In your annotation processing, you then should check whether the annotation is set, whether the values are correct, and make the compilation fail.
The complete documentation is available in the documentation for the package javax.annotation.processing.
Also, a few tutorials are available on the Internet if you search for "java annotation processing".
I will not go deeper in the subject as I never used the technology myself before.
I have run into the same problems as you, and am using the following approach now. Store Metadata about columns as annotations and parse them at runtime. Store this information in a map. If you really want compile time errors to appear, most IDEs (Eclipse e.g.) support custom builder types, that can validate the classes during build time.
You could also use the compile time annotation processing tool which comes with java, which can also be integrated into the IDE builds. Read into it and give it a try.
In Java the most similar approach to "static classes" are the static enums.
The enum elements are handed as static constants, so they can be accesed from any static context.
The enum can define one or more private constructors, accepting some intialization parameters (as it could be a table name, a set of columns, etc).
The enum class can define abstract methods, which must be implemented by the concrete elements, in order to compile.
public enum EntityMetadata {
TABLE_A("TableA", new String[]{"ID", "DESC"}) {
#Override
public void doSomethingWeirdAndExclusive() {
Logger.getLogger(getTableName()).info("I'm positively TableA Metadata");
}
},
TABLE_B("TableB", new String[]{"ID", "AMOUNT", "CURRENCY"}) {
#Override
public void doSomethingWeirdAndExclusive() {
Logger.getLogger(getTableName()).info("FOO BAR message, or whatever");
}
};
private String tableName;
private String[] columnNames;
private EntityMetadata(String aTableName, String[] someColumnNames) {
tableName=aTableName;
columnNames=someColumnNames;
}
public String getTableName() {
return tableName;
}
public String[] getColumnNames() {
return columnNames;
}
public abstract void doSomethingWeirdAndExclusive();
}
Then to access a concrete entity metadata this would be enough:
EntityMetadata.TABLE_B.doSomethingWeirdAndExclusive();
You could also reference them from an Entity implemetation, forcing each to refer an EntityMetadata element:
abstract class Entity {
public abstract EntityMetadata getMetadata();
}
class A extends Entity {
public EntityMetadata getMetadata() {
return EntityMetadata.TABLE_A;
}
}
class B extends Entity {
public EntityMetadata getMetadata() {
return EntityMetadata.TABLE_B;
}
}
IMO, this approach will be fast and light-weight.
The dark side of it is that if your enum type needs to be really complex, with lot of different params, or a few different complex overriden methods, the source code for the enum can become a little messy.
Mi idea, is to skip the tables stuff, and relate to the "There are not abstract static methods". Use "pseudo-abstract-static" methods.
First define an exception that will ocurr when an abstract static method is executed:
public class StaticAbstractCallException extends Exception {
StaticAbstractCallException (String strMessage){
super(strMessage);
}
public String toString(){
return "StaticAbstractCallException";
}
} // class
An "abstract" method means it will be overriden in subclasses, so you may want to define a base class, with static methods that are suppouse to be "abstract".
abstract class MyDynamicDevice {
public static void start() {
throw new StaticAbstractCallException("MyDynamicDevice.start()");
}
public static void doSomething() {
throw new StaticAbstractCallException("MyDynamicDevice.doSomething()");
}
public static void finish() {
throw new StaticAbstractCallException("MyDynamicDevice.finish()");
}
// other "abstract" static methods
} // class
...
And finally, define the subclasses that override the "pseudo-abstract" methods.
class myPrinterBrandDevice extends MyDynamicDevice {
public static void start() {
// override MyStaticLibrary.start()
}
/*
// ops, we forgot to override this method !!!
public static void doSomething() {
// ...
}
*/
public static void finish() {
// override MyStaticLibrary.finish()
}
// other abstract static methods
} // class
When the static myStringLibrary doSomething is called, an exception will be generated.
I do know of a solution providing all you want, but it's a huge hack I wouldn't want in my own code nowadays:
If Entity may be abstract, simply add your methods providing the meta data to that base class and declare them abstract.
Otherwise create an interface, with methods providing all your data like this
public interface EntityMetaData{
public String getTableName();
...
}
All subclasses of Entity would have to implement this interface though.
Now your problem is to call these methods from your static utility method, since you don't have an instance there. So you need to create an instance. Using Class.newInstance() is not feasable, since you'd need a nullary constructor, and there might be expensive initialization or initialization with side-effects happening in the constructor, you don't want to trigger.
The hack I propose is to use Objenesis to instantiate your Class. This library allows instatiating any class, without calling the constructor. There's no need for a nullary constructor either. They do this with some huge hacks internally, which are adapted for all major JVMs.
So your code would look like this:
public static function afunction(Class clazz) {
Objenesis objenesis = new ObjenesisStd();
ObjectInstantiator instantiator = objenesis.getInstantiatorOf(clazz);
Entity entity = (Entity)instantiator.newInstance();
// use it
String tableName = entity.getTableName();
...
}
Obviously you should cache your instances using a Map<Class,Entity>, which reduces the runtime cost to practically nothing (a single lookup in your caching map).
I am using Objenesis in one project of my own, where it enabled me to create a beautiful, fluent API. That was such a big win for me, that I put up with this hack. So I can tell you, that it really works. I used my library in many environments with many different JVM versions.
But this is not good design! I advise against using such a hack, even if it works for now, it might stop in the next JVM. And then you'll have to pray for an update of Objenesis...
If I were you, I'd rethink my design leading to the whole requirement. Or give up compile time checking and use annotations.
Your requirement to have static method doesn't leave much space for clean solution. One of the possible ways is to mix static and dynamic, and lose some CPU for a price of saving on RAM:
class Entity {
private static final ConcurrentMap<Class, EntityMetadata> metadataMap = new ...;
Entity(EntityMetadata entityMetadata) {
metadataMap.putIfAbsent(getClass(), entityMetadata);
}
public static EntityMetadata getMetadata(Class clazz) {
return metadataMap.get(clazz);
}
}
The way I would like more would be to waste a reference but have it dynamic:
class Entity {
protected final EntityMetadata entityMetadata;
public Entity(EntityMetadata entityMetadata) {
this.entityMetadata=entityMetadata;
}
}
class A extends Entity {
static {
MetadataFactory.setMetadataFor(A.class, ...);
}
public A() {
super(MetadataFactory.getMetadataFor(A.class));
}
}
class MetadataFactory {
public static EntityMetadata getMetadataFor(Class clazz) {
return ...;
}
public static void setMetadataFor(Class clazz, EntityMetadata metadata) {
...;
}
}
You could get even get rid of EntityMetadata in Entity completely and leave it factory only. Yes, it would not force to provide it for each class in compile-time, but you can easily enforce that in the runtime. Compile-time errors are great but they aren't holy cows after all as you'd always get an error immediately if a class hasn't provided a relevant metadata part.
I would have abstracted away all meta data for the entities (table names, column names) to a service not known by the entities them selfs. Would be much cleaner than having that information inside the entities
MetaData md = metadataProvider.GetMetaData<T>();
String tableName = md.getTableName();
First, let me tell you I agree with you I would like to have a way to enforce static method to be present in classes.
As a solution you can "extend" compile time by using a custom ANT task that checks for the presence of such methods, and get error in compilation time. Of course it won't help you inside you IDE, but you can use a customizable static code analyzer like PMD and create a custom rule to check for the same thing.
And there you java compile (well, almost compile) and edit time error checking.
The dynamic linking emulation...well, this is harder. I'm not sure I understand what you mean. Can you write an example of what you expect to happen?
Related
I need to build my own library to handle events coming from an event bus, the first solution I came up with was an abstract class made like this one:
public abstract class MyEventListener<T> extends RealEventListener{
private final Class<T> type; //the event class type
private final String stream; //the stream
public abstract onEvent(T type); //the method my subclasses have to implement
#Overrides
public void onEvent(byte[] evt){ //takes the original, clunky method and evolves it with typing
//convert and do stuff
onEvent(convertedEvent); //call method
}
}
so, the classes only do:
#Component
public class Child extends MyEventListener<AType>{
public Child(){
super(AType.class, "stream"); //registers
}
#Overrides
public void onMessage(AType evt){ //do stuff
}
I find this approach somewhat limiting and outdated (at least seeing the latest libraries). An example I can think of is that, this way, you are forced to handle separate events in separate classes.
So, I though of using annotations to have something like this:
#EventListener("stream") //1. you define the stream in this custom class annotation
public class Child { //so no need to extend
#ListenTo(type=AType.class) //2. you define the type on methods, this way a single class can handle more
public void onMessage(AType event, //any other param){
}
Now, for the magic behind, I though about using a startup annotation processing to retrieve the methods:
public void initialize(#EventListener List<Object> listeners) { //I inject all objects
listeners.stream().map(..).collect(..) //use reflection to get all methods annotated with #ListenTo and put them inside of map <String, Method>
eventBus.registerListener(new MyEventListener(target, methodMap)); //
}
Now, the listener will take somewhat the type from the original byte event and call the method:
String className = getClassFromEvent(evt);
listenerMap.get(className).invoke(target, evt);
According to you is this approach valid and, most importantly, efficient? Or, excluding the initialization phase, it could lead to performance problems at runtime? Of course I should make static checks at initialization to make sure that the annotated methods declare the event as parameter but it seems cleaner to me than the first one.
I have a Java class Model which models some data from my remote database. I want all data models in my project to be able to supply a builder from a Map<String, Object> instance (in practice, I'm working with SnapshotParser<Model> parsers with Firestore, but I'll just call getData() in every model). This should look something like:
public class Model {
private String name;
public Model(String name) { this.name = name; }
public static SnapshotParser<Model> getDocParser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"));
};
}
}
Note that I'll have several models (Model2, Model3...) which will also be required to provide such an interface. To enforce this behavior, I created a DocParserSupplier generic class for my model classes to implement:
public interface DocParserSupplier<T> {
static SnapshotParser<T> getDocParser();
}
This doesn't work for two reasons (as Android Studio informs me):
static methods of interfaces must have a default implementation. I can't do that without knowing T.
I get the "T cannot be referenced in static context" error.
If remove the static keyword from the above interface, I can do what I want but it would require I create an actual instance of the Model to get the parser. It would work but it makes more sense if the method is static.
Is there a Java way to do what I want?
EDIT: My specific use case is in matching RecyclerViews to documents in my database. Constructing the FirestoreRecyclerOptions object requires a parser to convert key-value data to a Model:
FirestoreRecyclerOptions<Model1> fro1 = new FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, Model1.getDocParser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, Model2.getDocParser())
.build();
Interfaces enforce behavior of instances, so that references to any object which has that behavior can be passed around in a type-safe way. Static methods on the other hand, don't belong to any particular instance of an object; the class name is essentially just a namespace. If you want to enforce behavior, you will have to create an instance somewhere (or use reflection, if it is absolutely necessary to ensure a class has a particular static method).
Unless this system is going to be opened up for extension, where others can define their own models, I would say ditch the DocParserSupplier interface altogether and call the static methods exactly as you are now, or factor them out into a factory interface + implementation. The factory option is nice because you can replace the production implementation with a fake implementation that returns dummy parsers for tests.
Edit: Doc Parser Factory
public interface DocParserFactory {
SnapshotParser<Model1> getModel1Parser();
SnapshotParser<Model2> getModel2Parser();
...
SnapshotParser<Model1> getModelNParser();
}
...
// The implementation of each getModelXParser method
class DocParserFactoryImpl {
SnapshotParser<Model1> getModel1Parser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"))};
}
...
}
...
private DocParserFactory docParserFactory;
// You can inject either the real instance (DocParserFactoryImpl) or a
// test instance which returns dummy parsers with predicable results
// when you construct this object.
public ThisObject(DocParserFactory docParserFactory) {
this.docParserFactory = docParserFactory;
}
...
// Your code
public void someMethod() {
...
FirestoreRecyclerOptions<Model1> fro1 = new
FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, docParserFactory.getModel1Parser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new
FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, docParserFactory.getModel2Parser())
.build();
...
}
It's not so much to do with static or non-static, as it is with the fact that you cannot create an instance of a generic object without passing the type parameter(s) one way or another. In fact, I answered a similar question a few days ago, when somebody wanted to use enums to get the required builder.
In short, you cannot write a method <T extends AbstractBuilder> T builder(final SomeNonGenericObject object) (or, in this case, <T extends AbstractBuilder> T builder()) without passing T in some form. Even though it will make sense at runtime, the compiler can't figure out what generic type to use if you don't tell it which one it is.
In Java 8, you can solve this elegantly with method references. I don't know much about Android, but I believe you're still on Java 6 there, so this wouldn't work.
Anyway, you can have something like the following:
public <T extends AbstractBuilder> T builder(final Supplier<T> object) {
return supplier.get();
}
final Supplier<AbstractBuilder> model1BuilderSupplier = Model1Builder::new;
builder(model1BuilerSupplier)
.setQuery(query1, Model1.getDocParser())
.build();
It's not exactly what you want, but the way you're trying to go about it will not work.
Can the JVM perform runtime optimization in the following scenario?
We've got the following situation, we have this interface:
public interface ECSResource {
default int getFor(final Entity entity) {
return ResourceRetriever.forResource(this).getFor(entity);
}
}
And a concrete implementation such as:
private static enum TestResources implements ECSResource {
TR1, TR2;
}
Would the JVM be able to figure out (at runtime) that an enum instance such as TestResources.TR1 belongs to a single ResourceRetriever like ResourceRetriever.forResource(TestResources.TR1)?
In the naive implementation every call to TestResources.TR1.getFor(...) would create a new ResourceRetriever instance.
In this case though, we know that (by code inspection) a call to ResourceRetriever.forResource(this) will call the following:
public class ResourceRetriever {
private final ECSResource resource;
ResourceRetriever(ECSResource resource) {
this.resource = resource;
}
public static ResourceRetriever forResource(ECSResource resource) {
return new ResourceRetriever(resource);
}
//lots of methods
}
Hence there is nothing that can change at runtime due to random results, rounding errors, etc.
Hence the question: Can the JVM map every enum ECSResource instance to its unique corresponding ResourceRetriever.forResource(this) instance?
Note that it is possible to do such thing by your own, via the following:
private static enum TestResources implements ECSResource {
TR1, TR2;
private static final Map<TestResources, ResourceRetriever> retrieverMapping;
static {
retrieverMapping = Arrays.stream(TestResources.values())
.collect(Collectors.toMap(res -> res, ResourceRetriever::forResource));
}
#Override
public int getFor(final Entity entity) {
return retrieverMapping.get(this).getFor(entity);
}
}
The semantics of the new keyword almost certainly prohibit what you're wanting to do. (See references both in The Java Language Specification and The Java Virtual Machine Specification.) Your forResource method is always going to return a new object. I don't know of any JVMs that would do what you're trying to do, given that there is no mechanism to determine that only one ResourceRetriever should be created for any given ECSResource. This looks like a form of memoization to me, which would be handled by the language (e.g. Groovy, which has an annotation specifically for this) and not by the runtime (JVM). If Java had reified generics, you could possibly hack such a feature with something like ResourceRetriever<? extends ECSResource> but I can't say whether that would actually work, much less whether it would be a good idea or not.
There is a part in my java code where I am extending a class from a library which I haven't written.
#override
public Object getPropertyValue(Object id) {
if(id.equals(model.PROPERTY_RENAME))
model.setName((String)value);
else if(id.equals(model.PROPERTY_COLOUR))
model.setColor((Color)value);
}
Now in this case how should I modify this code to make it scalable. There would be many more properties like location, dimension, etc. Now this model is instance of an abstract class AbsModel.
So every class implementing the AbsModel would have different properties. So the class architecture should be there, so that this part of code remains unchanged, no matter how many more model classes I add.
It looks like you want to carry out some operation on the model when this method (getPropertyValue) is called. I would create a Map of id onto the interface ModelOperation defined as follows:
public interface ModelOperation {
void operate(Object value);
}
Then the map would be defines as follows:
map.put(model.PROPERTY_RENAME, new RenameOperation(model));
Your extension class would then look like this:
#Override
public Object getPropertyValue(Object id) {
map.get(id).operate(model);
// etc...
}
For example, RenameOperation would be defined like this:
public class RenameOperation implements ModelOperation {
public RenameOperation(Model model) {
// etc...
}
public void operate(Object value) {
model.setName((String)value);
}
}
This allows you to support as many model operations as you like and means you don't have to change the extension class you have to write. The above is just an outline. You could use generics on the ModelOperation implementations to avoid the cast of the value in each one.
I guess reflection is probably the answer here if you can rely on some naming to help direct you.
It's not going to be nice, but the idea would be that you'd have a method that would reflect on the type and look up the appropriate method. The code belwo
public Object setPropertyValue(Object id) {
String className = id.getClass().getSimpleName();
// Hope that the method is called set<CLASS> and takes a single parameter that is the class
Method method = model.class.getMethod("set" + className, id.getClass());
// Invoke the method (TODO deal with all of the exceptions)
method.invoke(model, id);
}
There are multiple ways of doing this -- though it depends on what do you mean by "scalable" (being able to cope with lots of requests per second or being able to cope with lots of properties?):
one way -- if you're going to go down the path you have outlined in your code is to have those properties that are used very often at the top of your if/then/else block -- so their execution path is very short. this would "scale up" well for lots of requests as not too much time is being spent in actually executing the method (in most cases at least!)
another way -- and this scales up well for lots of properties and easiness of maintaining the code but you will take a hit on execution time: have a Map that maps property names to setxxx() method names, then you can use reflection to invoke these methods on the target object (id in your case) on each call. Classes extended your class will only have to provide a getMap() method which will return the mapping name-to-setter method, which can be a static member and initialized on class load.
Store your properties in a Map -- in which case setName() is the same as map.put( PROPERTY_RENAME, value)
Since in Java functions are not first class citizens, the "nice" route would be very awkward: define an enum with one value per each constant above (i.e. for each property), and a virtual method e.g. update(Object value, then override the method in each enum to update the corresponding property. If you can, redefine the constants PROPERTY_RENAME etc. themselves as enums. This still results in code bloat.
The other way is to use reflection. If you can use the same ids as the property names you want to update, you only need to invoke the setter for the property (as illustrated in other answers). Otherwise you may need to introduce a mapping from ids to property names.
A version not using reflection, call the base class's implementation:
public Object getValue(Object id) {
Object ret = super.getValue(id);
if (ret == null) {
// Subclass specific properties
}
return ret;
}
A common way around this is to use reflection like
public Object getValue(IdType id) {
Method getter = model.getClass().getMethod("get" + id);
return getter.invoke(model); // throws Exceptions.
}
OR
public void setValue(IdType id, Object value) {
Method setter = model.getClass().getMethod("set" + id, value.getClass());
setter.invoke(model, value); // throws Exceptions.
}
I solved this issue by creating an interface. So the code is.
public interface IModel
{
public void setProperty(String propertyName);
}
Rest of the classes were
public class HelloModel implements IModel
{
public void setProperty(String propertyName)
{ code for handling the properties goes here ... }
}
So in this case every class has to handle it's own property setters.
Is this the best way to handle abstraction ? I think this model is very scalable ...
Say you have an API that is not accessible to change:
List<LegacyObject> getImportantThingFromDatabase(Criteria c);
Imaging Legacy Object has a ton of fields and you want to extend it to make getting at certain information easier:
class ImprovedLegacyObject extends LegacyObject {
String getSomeFieldThatUsuallyRequiresIteratorsAndAllSortsOfCrap() {
//cool code that makes things easier goes here
}
}
However, you can't just cast to your ImprovedLegacyObject, even though the fields are all the same and you haven't changed any of the underlying code, you've only added to it so that code that uses LegacyObject still works, but new code is easier to write.
Is it possible to have some easy way to convert LegacyObject to ImprovedLegacyObject without recreating all of the fields, or accessors? It should be a fast opperation too, I konw you could perform something by using reflections to copy all properties, but I don't think that would be fast enough when doing so to masses of LegacyObjects
EDIT: Is there anything you could do with static methods? To decorate an existing object?
You would have to perform the copying yourself. You can either have a constructor that does this (called a copy constructor):
public ImprovedLegacyObject(LegacyObject legacyObject) {
...
//copy stuff over
this.someField = legacyObject.getSomeField();
this.anotherField = legacyObject.getAnotherField();
...
}
or you can have a static factory method that returns an ImprovedLegacyObject
public static ImprovedLegacyObject create(LegacyObject legacyObject) {
...
//copy stuff over
...
return improvedLegacyObject;
}
If you're planning on extending this behavior to other legacy objects, then you should create an interface
public interface CoolNewCodeInterface {
public String getSomeFieldThatUsuallyRequiresIteratorsAndAllSortsOfCrap() {
}
public String getSomeFieldInAReallyCoolWay() {
}
}
Then your ImprovedLegacyObject would look like this:
public ImprovedLegacyObject extends LegacyObject implements CoolNewCodeInterface {
//implement methods from interface
}
How about making a copy constructor for your Improved Legacy Object that takes a Legacy Object as an argument. Then just create new objects from the old ones.