Inheriting class with primary constructor - java

I have a parent class as following,
interface ITask { }
open class Task(val targetServer: Server) : ITask { }
Then there a child inheriting it and overriding the primary constructor as following,
data class FileTask(val sourceServer: Server, targetServer: Server) : Task(targetServer = targetServer) {
}
This is throwing a compilation error in eclipse as
Data class primary constructor must have only property (val / var) parameters
Removing the data keyword from the class header will kill the error, but I don't understand why.
Keeping the data keyword and adding var to the targetServer gives another error
'targetServer' hides member of supertype 'Task' and needs 'override' modifier
Adding override to the targetServer to be override var targetServer: Server throws another error
'targetServer' in 'Task' is final and cannot be overridden
I need some help to understand these errors.

The initial error is because a data class can't have parameters in its primary constructor other than val or var properties. Removing the data keyword lifts this restriction.
It's been mentioned that data classes generally don't play well with inheritance. They're supposed to be used as simple data transfer objects, and aren't really suitable for participating in hierarchies, because it becomes hard to understand which properties are going to be considered in the implementations of the generated methods. Your best bet might be to not use them at all here.
For more about data classes and inheritance, here is the proposal that was implemented in Kotlin 1.1.
To get back to the specific problem, if you really have to make this class a data class, you can mark the property in the base class as open and then override it in FileTask, like so:
open class Task(open val targetServer: Server) : ITask
data class FileTask(val sourceServer: Server, override val targetServer: Server): Task(targetServer = targetServer)
This basically hides the property declared in Task, and always accesses the property in FileTask instead.
I don't know what your exact requirements for your classes are, but one thing you could do to clean this up and make it a bit nicer would be to make Task and its targetServer property abstract, like so:
abstract class Task : ITask {
abstract val targetServer: Server
}
data class FileTask(val sourceServer: Server, override val targetServer: Server) : Task()
This way you wouldn't have the unnecessary property (and backing field) in the base class, and you'd be forced to have a targetServer property in all the classes that inherit from Task. You could also take this a step further, and put the property in the ITask interface as well.
interface ITask {
val targetServer: Server
}

I know this is a very old post, but I was struggling with the same issue and making my superclass abstract was not a solution.
You just need to do the following:
change this
open class Task(val targetServer: Server) : ITask { }
to (Please note, I have made targetServer variable to open)
open class Task(open val targetServer: Server) : ITask { }

Related

Call Kotlin object with class delegation from Java as a static method

This may be a bit difficult to describe, so I'll try to give a concrete example of what I'm trying to do.
Suppose we have a Facade interface and class (in Java), like this:
interface FacadeInterface<T> {
void method(String from, String via);
}
class Facade<T> implements FacadeInterface<T> {
private Class<T> mClazz;
public Facade(Class<T> clazz) {
mClazz = clazz;
}
#Override
public void method(String from, String via) {
System.out.println("Method called from " + from + " via " + via);
}
}
In my applications, I need to have multiple singletons which hold an instance of the facade. The real facade has additional setup/config parameters but those are irrelevant here.
Before I started using kotlin, I would have a class which holds a static instance of the facade (not really a singleton, but in my case, it served a similar purpose) which proxied the calls to the facade, like this:
public class Singleton {
private static final FacadeInterface<String> sFacade = new Facade<>(String.class);
private Singleton() {
}
public static void method(String from, String via) {
sFacade.method(from, via);
}
}
Now, with Kotlin we have class delegates which allow me to write something like this:
object SingletonKt : FacadeInterface<String> by Facade(String::class.java)
This is great - no more boilerplate and I can call SingletonKt from Kotlin classes the same way I called the java Singleton:
Singleton.method("Kotlin", "Singleton")
SingletonKt.method("Kotlin", "SingletonKt")
But, a slight problem arises when I use SingletonKt from Java. Then I have to specify INSTANCE:
Singleton.method("Java", "Singleton");
SingletonKt.INSTANCE.method("Java", "SingletonKt");
I am aware of the #JvmStatic annotation, but the only place I can put it in the SingletonKt file without causing compile errors is right before FacadeInterface and it doesn't seem to do the trick.
Is there a way to set up this class delegate so that I can call it from Java as if it were a static method, without introducing the boilerplate of creating proxy methods for SingletonKt (which would defeat the purpose of the class delegate)?
It's sadly not possilble!
The Kotlin Delegation is a nice way to reduce boilerplate code. But it comes with the inability to actually access the delegate within the class body.
The second issue you're facing regarding #JvmStatic is actually more drastic to your cause than the first and also applies to you when implementing the delegation manually:
Override members cannot be '#JvmStatic' in object
So instead of exposing the method() through the INSTANCE only, you could delegate it to a staticMethod() on the object. This still differs from your intent, but comes close to it.
object SingletonKt : FacadeInterface<String> by Facade(String::class.java)
#JvmStatic fun staticMethod(from: String, via: String) = method(from, to)
}
I don't know if it is possible to have delegated methods as static methods inside an object in Kotlin.
However, as you are interested in creating singletons that proxy a class, you could use package-level constants in Kotlin:
val SingletonKt : FacadeInterface<String> = Facade(String::class.java)
Now, you can call SingletonKt.method just like you would in Java. Note that you need to use a static import in Java to be able to use the SingletonKt constant.
This also allows you to use features like lazy to only create the singleton (or, in this case, instance) when you need it.

Cannot find field in mongo collection using morphia

I have an abstract Scala class as a Mongo collection.
#Entity("aclTemplate")
abstract class AclTemplate(#(Id#field) var id: String) extends Serializable
Another class extends the above
#Entity("aclTemplate")
class GroupACLTemplate(id: String, var groupRoleAccess: Set[GroupRoleAccess]) extends AclTemplate(id) with Serializable
There are some docs of GroupACLTemplate in the collection. I am trying a simple query
createQuery().disableValidation().field("groupRoleAccess.groupId").equal(groupId).asList();
This throws a ValidationException
org.mongodb.morphia.query.ValidationException: The field 'groupRoleAccess.groupId' could not be found in 'com.model.acl.AclTemplate'
I do not think it is because of the long standing polymorphism issue in morphia. Because when I try to access just groupRoleAccess, it is able to. However, it is not able to access inside that set. It is a normal Java set. This is the GroupRoleAccess class
class GroupRoleAccess(var groupId: String, var roleId: String) extends Serializable
Am I missing something here?
I managed to hack something up. Apparently, since the collection is an abstract class, Mongo/Morphia does not look for attributes that are present in its subclasses. So I used createQuery and passed the class of the subclass.
ds.createQuery(clazz).disableValidation().field("groupRoleAccess.groupId").equal(groupId).asList();
But I still wonder how it was able to extract groupRoleAccess before
You should try 1.3.0-SNAPSHOT. I just fixed a bug similar to this and it probably fixes your issue, too.

Binding a map of classes to instances inside guice module

I am currently trying to add the entries of a map consisting of Map<? extends CustomModule, CustomModule> (from an additional, custom module system) as bindings within a guice module.
My code so far looks like this:
manager.getRegistry().forEach(new BiConsumer<Class<? extends CustomModule>, ModuleRegistry.Entry>() {
#Override
public void accept(Class<? extends CustomModule> moduleClass, ModuleRegistry.Entry entry) {
bind(moduleClass).to(entry.getModule()); // getModule() returns the instance which implements moduleClass
}
});
Guice sadly needs the direct class instead of a wildcard ("? extends").
Since I already got the "bindings", is there another way to add them to the injector?
Thanks in advance!
So after trying various other possible ways, I finally found one that works.
Since the original problem was that Guice required a "capture" of something (in this case "capture of ? extends Module instance", basically means something that is an instance of something that is a module) and failed, I had to cast my already known module class to its raw type, like this:
final Class moduleClass = (Class) aClass;
final Binding binding = injector.getExistingBinding(Key.get(moduleClass));
if (binding == null) {
bind(moduleClass).toInstance(entry.getModule());
}
I also had to add a null check in my case, but it also includes the way how to cast your unknown class to guice's "Key" helper.

Prototyping in Java instead of extending

Is Javascript-like prototyping anyhow achievable, even using Reflection? Can I wrap my object inside another one, just to extend its functionality with one or two more methods, without wiring all its original nonprivate methods to the wrapper class, or extends is all I get?
If you are looking for extension methods, you could try Xtend. Xtend is language that compiles to java code and eliminates boilerplate code.
The following text is stolen from the Xtend Docs for extensions:
By adding the extension keyword to a field, a local variable or a parameter declaration, its instance methods become extension methods.
Imagine you want to have some layer specific functionality on a class Person. Let us say you are in a servlet-like class and want to persist a Person using some persistence mechanism. Let us assume Person implements a common interface Entity. You could have the following interface
interface EntityPersistence {
public save(Entity e);
public update(Entity e);
public delete(Entity e);
}
And if you have obtained an instance of that type (through a factory or dependency injection or what ever) like this:
class MyServlet {
extension EntityPersistence ep = Factory.get(typeof(EntityPersistence))
...
}
You are able to save, update and delete any entity like this:
val Person person = ...
person.save // calls ep.save(person)
person.name = 'Horst'
person.update // calls ep.update(person)
person.delete // calls ep.delete(person)
I don't think you can do this in Java. You can though in Groovy, using metaclasses
String.metaClass.world = {
return delegate + " world!"
}
println "Hello".world()

Cast an object dynamically from a string

I'm writing a servlet-filter as the solution of this question:
Is it a good idea to filter inside a JSF template?
now, the idea is to create a big filter to check all privilegies and give the access or not to a certain user.
I create a Map to contains all privilegies for all sub applications and it has the sub application's id (a Long value) as Key and for the value another Map that contains other important informations.
The controller classes are named class1Controller, class2Controller ecc and the subapplications are stored in many folder named class1, class2 ecc...
The last thing that I must say is that all classes have a parameter called applicationID that is the same key of the Map that I mentioned previously.
So, what I would do?
I can retrieve the subapplication visited by the user using getRequestURI() method from HttpServletRequest, the problem is that I should take the application id from the class linked to that application, so I wrote this code:
Long id= ((Class.forName(packageName+applicationName+"Controller"))session.getAttribute(applicationName+"Controller")).getApplicationId();
The problem is that the compiler returns that it can't find method getApplicationId()!
Can I do something to resolve this problem? Or I must find another way to do that?
The last thing that I must say is that all classes have a parameter called applicationID
It sounds like you want an interface with the getApplicationId method in; make all the controllers implement that interface, and then all you need to do is cast to that interface.
// TODO: Work out a better interface name than "Application" :)
Object attribute = session.getAttribute(applicationName+"Controller");
Long id = ((Application) attribute).getApplicationId();
(You might want to use an abstract base class as described by BalusC - they're variations on the same theme, really.)
You're calling getApplicationId() on a Class instance, but it does not have that method at all.
The normal approach is to let all those classes extend some common base abstract class or an interface which has the method definied and then cast to that base abstract class or interface instead.
E.g. with a base abstract class:
public class FooController extends BaseController {}
public class BarController extends BaseController {}
etc..
Where the base abstract class look like this:
public abstract class BaseController {
public Long getApplicationId() {
return applicationId;
}
}
Then you can get it as follows:
Long id = ((BaseController) session.getAttribute(applicationName + "Controller")).getApplicationId();

Categories