Generic inheritance Issue - java

I have a couple interfaces to support our post processing of entities:
WorkFlowProcessor
public interface WorkFlowProcessor {
void PostProcess(List<WorkFlowStrategy> strategies);
}
WorkFlowAction
public class WorkFlowAction implements WorkFlowProcessor{
...
...
public void PostProcess(List<WorkFlowStrategy> strategies){
for(WorkFlowStrategy strategy : strategies){
strategy.process(this)
}
}
}
WorkFlowStrategy
public interface WorkFlowStrategy {
void process(WorkFlowProcessor itemToProcess);
}
TicketWorkFlowStrategy
public class TicketWorkFlowStrategy implements WorkFlowStrategy {
...
...
#Overried
public void process(WorkFlowAction action){ //must override or implement a supertype method
// do a lot of processing
}
}
I'm trying to figure out why I cannot get it to compile with the WorkFlowAction class. Normally this works just fine. Any thoughts on how I can get this to run correctly?

That's because you've got to declare it with the same signature as the method in the interface:
<T extends WorkFlowProcessor> void process(T itemToProcess)
Declaring the method like this in the interface doesn't mean you can specialize implementations of it for more specific parameters. This method has to accept any WorkflowProcessor.
Because of that fact, the type variable here is pretty useless: you may as well just declare it thus in the interface, which makes it cleaner to implement too:
void process(WorkflowProcessor itemToProcess);
Method-level type variables aren't actually useful unless you doing one or more of the following:
Returning the same type as a non-generic parameter
Constraining a generic parameter to be related either to another parameter or the return type.
If you want to specialize the process method for a particular subclass of WorkflowProcessor, you have to put this on the interface:
public interface WorkFlowStrategy<T extends WorkFlowProcessor> {
void process(T itemToProcess);
}
Then:
public class TicketWorkFlowStrategy implements WorkFlowStrategy<WorkflowAction> {
#Override
public void process(WorkFlowAction action){
// ...
}
}

The implication being made by the process method as defined in the WorkFlowStrategy interface is that implementations should be able to accept any WorkFlowProcessor as an argument to the method. The generic definition you added to this method does nothing to change this.
In your case, the generic definition probably belongs on the interface level, not on the method level. You can then be explicit about what types can be supported.

Related

Can I call a static method on a generic class parameter

I have a collection of classes that implement RaeInterface:
public interface RaeInterface {
public static String SCHEMA_ID(){return ""; };
}
Each of the implementing classes have a different SCHEMA_ID() defined.
Id' like to pass a class to a method and use the static SCHEMA_ID() method on the class. I can pass the class to a method just fine, but getting at the static SCHEMA_ID() proves frustratingly hard.
public <T extends RaeInterface> void get( Class klass){
klass.SCHEMA_ID(); // <-- cannot resolve method.
}
Any suggestions on how to resolve this or is this even possible in Java 8?
Static methods cannot override in implementation of the Interface. If you want to override use default methods in interface.
Interface :
public interface RaeInterface {
default String SCHEMA_ID() {
return "";
}
}
Your mention method :
public <T extends RaeInterface> void get(T klass) {
klass.SCHEMA_ID();
}
Implement class :
class B implements RaeInterface {
#Override
public String SCHEMA_ID() {
return "B";//the ID
}
}
class C implements RaeInterface {
#Override
public String SCHEMA_ID() {
return "C";//the ID
}
}
I think you want an instance method in your interface:
public String schemaId();
Each implementing class can (and must if not abstract) implement this method. It doesn’t need to use any instance stuff for the implementation.
Your calling method gets much simpler and doesn’t need any generics:
public void get(RaeInterface instance){
instance.schemaId();
}
For inspiration you may look at how the java.util.Comparator interface is used. Usually classes implementing this interface don’t contain any instance variables, so you would think the compare method could just as well be static. Its probably only non-static to allow different implementations.
If you really insist on a static method, Sergey Lagutin is correct that reflection will solve your problem. But again, it’s getting more complicated and I don’t see why you should want such a solution.

Java, force implementation of method without knowing parameters

I have an abstract class that performs basic operations, now I want to force every derived class to have a method "check", but the point is I know nothing about this method. For example, the abstract class:
public abstract class Service<T extends Transport> {
public T getTransport(int id) {
[...]
}
public abstract boolean checkTransport(T transport, ...);
}
and two implementing classes:
public ServiceAAA extends Service<ClassA> {
public boolean checkTransport(ClassA t) {
[...]
}
}
public ServiceBBB extends Service<ClassB> {
public boolean checkTransport(ClassB t, Integer value, Integer otherValue) {
[...]
}
}
The ServiceBBB needs two parameter to check the object t of class ClassB.
Of course it's not working, is there a way to force the subclass to implement the checkTransport method without using the "Object ... " notation?
No, there isn't.
Let's pretend there were a way. How would you invoke this method, either from the abstract Service class, or from any call site that had a reference to this object typed as Service<...>? There'd be no way of knowing what the specific subclass's method expects, and thus no way of invoking the method.
One way around this is to pass the checker in as a class to Service; that is, to use composition instead of inheritance. If you do that, you can have the checker's interface take no extra arguments at all (a Predicate might work, for instance), and the specific subclasses that implement that checker could have the arguments passed at construction time.

Interface does not see concrete implementation

I have
ISomeInterface
public interface ISomeInterface{
public void myMethod();
}
AbstractClass
public abstract class AbstractClass implements ISomeInterface{
public void myMethod(){
//...here goes implemetations
}
}
ConcreteClass
public class ConcreteClass extends AbstractClass {
//...
}
Compiler prints than ConcreteClass is not abstract and does not override abstract method myMethod in ISomeInterface.
The idea is to give implementation to one abstract class and then inherit it in classes that extend it.
I think that ConcreteClass should gets implementation form AbstractClass since it's extending it. Right? What's the matter?
UPDATE
I haven't noticed until now that method is wrong and it has to be myMethod. Anyways, same error.
UPDATE2
The problem was that in AbstractClass them method had correct name but incorrect signature. After changing it according with interface the problem was solved :)
In AbstractClass you are creating a method myMethod(), but your interface method method() is not being implemented in ConcreteClass. The names are different.
Assuming that your sample code is complete, you need to implement method from your interface. In AbstractClass you have called it myMethod instead.
You can use the #Override annotation on any override methods. This will tell you if you have used the wrong parameter types, method name, or an incompatible return type (parameters and return types don't have to be the same; they can, for example, be covariant).
Additionally, in Java, we don't tend to prefix interface names with I (unlike the convention in C#). Your interface would usually be called SomeInterface and not ISomeInterface.
Also, the public on methods on interfaces is implicit, so you can leave it out. If you do include it you should probably include the abstract as well to include all of the implicit modifiers.
An updated code sample would be:
public interface SomeInterface{
void method();
}
public abstract class AbstractClass implements SomeInterface {
#Override
public void method(){
//...here goes implemetations
}
}
You are probably overriding the wrong method. What happens is that you are probably attempting to override a method in your abstract class but what you are actually doing is to just define a new method with a new name. In the interface, the method is named method but in your abstract class your method is named myMethod.
So, check this out:
public abstract class AbstractClass implements ISomeInterface{
// Not the same name as in the interface
public void myMethod(){
//...here goes implemetations
}
}
In order to solve it, simply change the method name in the subclass to the correct name.
public abstract class AbstractClass implements ISomeInterface{
// Now you have the correct name and inheritance will
// work as expected
#Override
public void method(){
//...here goes implemetations
}
}
This is the perfect case for explaining the #Override annotation as well ;)
When overriding a method, you might want to use the #Override annotation that instructs the compiler that you intend to override a method in the superclass. If, for some reason, the compiler detects that the method does not exist in one of the superclasses, then it will generate an error.
When you declare a method with the annotation #Override the overridden method must match the signature of the interface-method (or superclass method). Read more about #Override in the Oracle Docs.
And, if you are not trying to override the method named method in your abstract class you simply need to add that method to your concrete class like this:
public class ConcreteClass extends AbstractClass {
// Now we are implementing the correct method from the interface
// If not, there will be a compiler error.
#Override
public void method() {
}
//...
}
On a side note which may be relevant: methods can have the same name but with different argument lists. This is known as overloading (or overloaded methods) which you can read more about in this article.
Edit: Since the OP is using Java 5 this question may be interesting. The #Override annotation changed between Java 5 and Java 6. In Java 5 it was not allowed to use the #Override annotation when implementing a method from an interface, it was just allowed when overriding a method from a superclass.
Your interface defines
public void method();
but your abstract class has
public void myMethod(){
//...here goes implemetations
}
Which isn't the same! Add the Override annotation to catch that kind of issue at compile time.
#Override
public void myMethod(){ // <-- compile error.
//...here goes implemetations
}
From the linked Javadoc,
Indicates that a method declaration is intended to override a method declaration in a supertype.
Well the first thing that I notice is that your method is not named the same thing in the interface and the abstract class.

Abstract method with variable list of arguments

I haven't quite found an elegant way to solve this issue. I have an abstract class that several other classes are inheriting with an abstract method that can contain anywhere from zero to 4-5 arguments of varying types.
public abstract class Item {
public abstract void use();
}
For instance, I have a Book class that inherits this and takes no arguments when overriding use(), I have a Key class that inherits and takes a String and a Queue as arguments when overriding, etc...
I've tried using generics but I have to input the number used, such as Item, when it actually depends on the class.
public abstract class Item<T,U> {
public abstract void use(T arg1, U arg2); //Number of arguments/types could be more or less
}
I've tried sending a variable list of Objects but the object types are always variable and I've unsure as to the syntax to receive in the inheriting classes.
public abstract class Item<T> {
public abstract void use(T... arguments);
}
public class Book extends Item<?> {
public void use(?);
}
public class Book extends Item<String, Queue> { //Wrong number of arguments since I can't use Item<T...>
public void use(String str, Queue q); //fails
}
I may just be doing something wrong - can anyone offer any assistance or insight?
I've struggled with the same question, and there's not a perfect answer, but I can give you a few things to consider. First, you're basically trying to do something that is inherently against Object Oriented Programming, which is that you're trying to create a variable interface. The point of an interface is that code that gets an abstract version of the object (the Item rather than the Book, for example), knows how to invoke the use() method. This means that they must know what can be passed to the use() method. If the answer depends on the implementation of the abstract class or interface, then you need to ensure that the code using it actually knows what kind of implementation (Book, etc.) that it's using, otherwise it's not going to know how to invoke use() with the appropriate parameters anyway. It sounds like you need to refactor your code, in all honesty.
However, there is a way to answer your question as stated without refactoring the architecture. You could create a class that's data is all of the different types of parameters that could possibly be passed to the use() method, have the calling code set the fields of that class, and then pass that to the use() method. For example:
public class UseParameters {
private String string;
private Queue queue;
// Any other potential parameters to use(...)
public void setString(String string) {
this.string = string;
}
public String getString() {
return string;
}
// All of the other accessor methods, etc.
}
Then, you could define the use method in Item like this:
public abstract void use(UseParameters params);
And any code using an Item would have to set the parameters of the object appropriately:
Item item = // However you're going to get the item
UseParameters params = new UseParameters();
params.setString("good string");
params.setQueue(new Queue());
item.use(params);
I just want to point out that if the code above knows the Item is a Book (which is how it knows to set the String and Queue, then why not just get a Book and skip needing an abstract class with a variable use() method altogether? But I digress. Anyway, the Book would then implement the use() method like so:
#Override
public void use(UseParameters params) {
if(params.getString == null || params.getQueue() == null)
// throw exception
// Do what books do with strings and queues
}
I think that gets you what you want, but you should consider refactoring, I think.
What you want is the Value Object Pattern.
Define a class that encapsulates the various parameter types into one value object, and have the abstract method accept a parameter of this type. Each variation of parameters you were considering would have its own value class.
Then simply add a generic type to the class and have the abstract method accept a parameter of that type:
public abstract class Item<V> {
public abstract void use(V v);
}
To use it, suppose MyItem needs a value object of type MyValueClass:
public class MyItem extends Item<MyValueClass> {
public void use(MyValueClass v) {
}
}
If the types to be used as argument are always variable I don't see a reason to use generics. Just use plain Object type:
public abstract class Item {
public abstract void use(Object ... arguments);
}
public class Book extends Item {
public void use(Object ... arguments) { ... }
}
The best approach I can think of is to group the items according to the behavior of their use() method.
Example
public abstract class QueueableItem {
public abstract void use(String, Queue);
}
public abstract class OrdinaryItem{
public abstract void use(String);
}
If the grouped items share a common behavior (common as in same method signature & return value), you can define and extend a parent class that will contain the definition of this common behavior.
Yes, we can provide parameters to abstract method but it is must to provide same type of parameters to the implemented methods we wrote in the derived classes.

Java: Subclass of the type in a method signature

Ok. So I'm trying to set up a GUI for an application using the observer pattern. In standard fashion; if an Observable updates it calls the update method of all its observers, passing a ComponentUpdateEvent, as follows:
public interface Observable {
ArrayList<Observer> observers = new ArrayList<Observer>();
public void updateObservers();
public void addObserver(Observer observer);
public void removeObserver(Observer observer);
}
public interface Observer {
public void update(ComponentUpdateEvent updateEvent);
}
public abstract class ComponentUpdateEvent {
public abstract ComponentType getComponentType();
}
I have a number of different components, which implement Observable, in the 'model' side of the application. Each type of component has a seperate subclass of the Drawer class, which implements Observer, for rendering to a JPanel.
The problem is that I'm trying to make it so that when the update method of a Drawer subclass is called, that the updateEvent parameter passed can be a subclass of ComponentUpdateEvent.
However, obviously if I try and do this as follows:
#Override
public void update(ConsoleUpdateEvent updateEvent) throws Exception {
if (this.componentType != updateEvent.get)) {
throw new Exception("ComponentType Mismatch.");
}
else {
messages = updateEvent.getComponentState();
}
}
I get the compiler error:
The method update(ConsoleUpdateEvent) of type ConsoleDrawer must override or implement a supertype method.
Because the method signature isn't the same. I can't seem to get around this problem without having seperate observer classes for each type of component, is it possible to solve this problem with generics? Any help would be appreciated.
Your interface has to declare that it throws Exception to solve your compiler error. The reason for this is that you don't pass a class type around, you pass the Observer interface around. So, if one class that implements Observable throws an exception, the calling class will not know about it unless the interface specifies it.
In your Observer interface, your update() method doesn't throw Exception and your ConsoleDrawer.update() does. The 2 aren't the same according to java.
Either you remove throw Exception on ConsoleDrawer or add the exception on the Observer interface.
In general, Java allows you to weaken the returned value when overriding a method, or strengthen the parameters. In this case, however, you are trying to weaken the parameter.
Maybe generics can help. I have to admit that I haven't tried the code below, this is just from memory:
You can try to use generics in the signature of the Observer interface:
public interface Observer<T>
or
public interface Observer<T extends ComponentUpdateEvent>
In addition to that, I'd revise the signature of Observable interface.
public void addObserver(Observer<T extends ComponentUpdateEvent> observer)

Categories

Resources