JAVA Generics design - java

My current abstraction model does not work. I am not sure why and how should I fix it. Please refer the following classes.
public class ErrorCaptchaRequired extends AbstractError {
public String getCaptchaUrl(){
return this.captchaUrl;
}
}
public abstract class AbstractError<E extends AbstractError> {
public E getError(int errorCode){
if(error_code == 1)
return new ErrorCaptchaRequired("abc", "abc", "abc");
if(error_code == 2)
return new AnotherErrorType();
}
}
public class MyObject<E extends AbstractError>{
private E error;
public E getAbstractError(){
return error;
}
}
Later on I want to use it like this:
AbstractError<ErrorCaptchRequired> myError = myObject.getAbstractError();
String captchaUrl = myError.getCaptchaUrl();
Compilation error during return statement: Incompatible types But I am not sure why, as in my understanding since I've parametirized class I can return any type which extends from AbstractError and ErrorCaptchaRequired is extending it. Could you please suggest a fix or better design? Thanks for any help!

The problem is raw (untyped) types. Raw types have all generic info stripped from them - hence no type match.
The type of AbstractError is itself raw: Change:
public abstract class AbstractError<E extends AbstractError> {
To
public abstract class AbstractError<E extends AbstractError<E>> {
Next, ErrorCaptchaRequired extends the raw (untyped) form of AbstractError, so every instance of ErrorCaptchaRequired is then raw.
Change:
public class ErrorCaptchaRequired extends AbstractError {
To:
public class ErrorCaptchaRequired<E extends AbstractError<E>> extends AbstractError<E> {
And change:
public class MyObject<E extends AbstractError>{
To:
public class MyObject<E extends AbstractError<E>>{

Related

How to make a reference to a concrete subtype in an abstract method definition

Suppose I have the following definition:
public abstract class SomeAbstractClass {
public abstract List<SomeAbstractClass> getNextElements() ;
}
If I build a concrete class that extends SomeAbstractClass named for instance SomeConcreteClass I would like getNextElements to have the following signature:
public List<SomeConcreteClass> getNextElements()
Instead of:
public List<SomeAbstractClass> getNextElements()
In other words, I would want my abstract definition to have a type depending on the current concrete type. Can it be done ? If so, how ?
Just use Java generics:
public abstract class SomeAbstractClass<T extends SomeAbstractClass> {
public abstract List<T> getNextElements() ;
}
public class SomeConcreteClass extends SomeAbstractClass<SomeConcreteClass> {
#Override
public List<SomeConcreteClass> getNextElements() {
return new ArrayList<>();
}
}
Another possibility would be to use only generic methods as follows:
public abstract class SomeAbstractClass {
public abstract <T extends SomeAbstractClass> List<T> getNextElements();
}
public class SomeConcreteClass extends SomeAbstractClass {
#Override
public List<SomeConcreteClass> getNextElements() {
return new ArrayList<>();
}
}
The downside of this is that you now have an unchecked conversion at List<SomeConcreteClass> getNextElements() which may potentially trigger ClassCastException at runtime.

Using Factory Method to Create Generics

I have an abstract class (Candy) with a generic collection (Flavors). Candy has a factory method to produce concrete instances of itself. It also has methods to get an instance of the generic flavor appropriate to the concrete candy and to add the flavor to its collection.
I know the getter is working, because if I cast the flavor from the CandyStore, the methods unique to the concrete flavor work fine. But the very last line, the addFlavor(flavor), errs (Eclipse) on me. The error is: "The method addFlavor(capture#5-of ? extends IFlavor) in the type ICandy is not applicable for the arguments (IFlavor)." Can anyone explain what is going on?
Interface:
public interface ICandy <Flavor extends IFlavor> {
public Flavor getFlavorForCandy();
public void addFlavor(Flavor flavor);
}
Abstract Class:
public abstract class AbstractCandy<Flavor extends IFlavor> implements ICandy<Flavor> {
public static ICandy<? extends IFlavor> buildCandy(String flavor){
if(flavor.equals("Jolly Rancher")
return new JolRanchCandy();
}
public Flavor getFlavorForCandy() {
return (Flavor) new CandyFlavor();
}
public void addFlavor(Flavor flavor) {
... //implemented
}
}
Concrete Class:
public class JolRanchCandy extends AbstractCandy<JolRanchFlavor> {
... //implemented
}
Used By:
public class CandyStore {
private ICandy<? extends IFlavor> candy;
private IFlavor flavor;
public void createCandy() {
candy = AbstractCandy.buildCandy("Jolly Rancher");
flavor = candy.getFlavorForCandy(); //returns a JolRanchFlavor
flavor.setName("Apple"); //etc for creating flavor
candy.addFlavor(flavor); //no luck
}
}
Edit: For clarity, JolRanchFlavor extends CandyFlavor implements IJolRanchFlavor and CandyFlavor implements IFlavor.
Try this...
public <T extends IFlavor> void createCandy() {
ICandy<T> candy= (ICandy<T>) AbstractCandy.buildCandy("Jolly Rancher");
T flavor= candy.getFlavorForCandy();
flavor.setName("Apple");
candy.addFlavor(flavor);
}
The problem is the declaration of private ICandy<? extends IFlavor> candy. Since the type of the candy is unknown and therefore ? the compiler doesn't know exactly what kind of IFlavor addFlavor should take. You just need to define a generic holder for the IFlavor type so that it is preserved.

Java Generics extending List

I have the following classes:
public interface ServiceSynchronizableEntity {
....
}
public class BaseListResponse<T> {
....
}
public class BaseSynchronizableListResponse<T extends ServiceSynchronizableEntity> extends BaseListResponse<T> {
....
}
public class MySecondClass implements ServiceSynchronizableEntity {
....
}
public class MyFirstClass extends BaseSynchronizableListResponse<MySecondClass> {
....
}
public class What<S extends BaseSynchronizableListResponse<ServiceSynchronizableEntity>> {
}
Then I use it as:
What what = new What<MyFirstClass>();
When I want to use MyFirstClass as a type parameter which extend BaseListResponse<ServiceSynchronizableEntity>> it shows me
Main.java:26: error: type argument MyFirstClass is not within bounds of type-variable S
What what = new What<MyFirstClass>();
^
where S is a type-variable: S extends BaseSynchronizableListResponse<ServiceSynchronizableEntity> declared in class What
What is wrong?
Edit: One class was missing. Look at: http://ideone.com/D4snKP
Thanks!
The solution I previously posted (now deleted) was similar in that it required a change to the generic signature.
The important change is going from:
class What<S extends BaseSynchronizableListResponse<ServiceSynchronizableEntity>> {}
to:
class What<S extends BaseSynchronizableListResponse<? extends ServiceSynchronizableEntity>> {}
See http://ideone.com/wyXvcl for the fixed version

Java generics static type inference

I do have an abstract class with an delegation interface defined:
public abstract class MyAbstractClass extends AsyncLoader {
public interface MyAbstractClassDelegate<M> {
//The parameter in this method should be the concrete subtype of MyAbstractClass
public M performThisCall(MyAbstractClass concreteSubclassOfAbstractClass);
}
private MyAbstractClassLoaderDelegate delegate;
...
}
The Problem is, I do not want the delegate parameter to be MyAbstractClass, instead it should be the concrete subclass. Why? Because the implementation of the delegate needs the concrete subclass for further handling and I don't want to cast it...
I know I could define an Interface in each subclass, but it'll look the same in every subclass except for the parameter type
EDIT
Here is the perfect solution solving exactly what I wanted. Great thanks!
public abstract class MyAbstractClass {
public interface MyAbstractClassDelegate<M, Subtype extends MyAbstractClass> {
public M myMethod(Subtype t);
}
}
Is this possible with java 6 and if yes - how?
My solution would be:
public final class Example<T extends Example<T>> {
public interface Interface<M, Subtype extends Interface<M, Subtype>> {
public M myMethod(Subtype t);
}
}
You have no access to the generic from the outer class inside the interface (because the interface is static) so you have to declare it again.
If you use your interface you get something like this:
private static class Impl1 implements Interface<String, Impl1> {
#Override
public String myMethod(final Impl1 t) {
return null;
}
}
I don't know if it will help but here is my complete example:
public final class Example<M, T extends Example.Delegate<M, T>> {
public interface Delegate<M, Subtype extends Delegate<M, Subtype>> {
public M myMethod(Subtype t);
}
private T delegate;
private static class Impl1 implements Delegate<String, Impl1> {
#Override
public String myMethod(final Impl1 t) {
return null;
}
}
public static void main(String[] args) {
Example<String, Impl1> example = new Example<>();
example.delegate = new Impl1();
example.delegate.myMethod(example.delegate); //works but whout?
}
}
What you could do is to give your abstract class a type parameter with the concrete subclass, similar to the way Java's Enum does it.
Something along the lines of this:
public abstract class MyAbstractClass<S extends MyAbstractClass<S>> extends AsyncLoader {
public interface MyAbstractClassDelegate<M, S> {
public M performThisCall(S concreteSubclassOfAbstractClass);
}
...

How to extend the generic class properly?

My question is a generic syntax question. As answered in this thread, I created the abstract generic super class.
public abstract class Translator <T extends OriginalText, V extends LanguageTranslation> {
public abstract V translate(T originalText);
}
Now, I fail in defining the child class.
public class ChineseToEnglishTranslator extends Translator<ChineseText, EnglishTranslation> {
#Override
public EnglishTranslation translate(ChineseText text) {
return null;
}
}
Eclipse returns the error: Bound mismatch: The type ChineseText is not a valid substitute for the bounded parameter <T extends OriginalText> of the type Translator<T,V>. ChineseText is definitely a child class of OriginalText. What is the syntax of what I want to do?
Make sure ChineseText extends OriginalText.
I'm not getting any errors as you have said if ChineseText extends OriginalText.
Bound mismatch: The type ChineseText is not a valid substitute for the
bounded parameter of the type
Translator.
This error appears only when ChineseText doesn't extends OriginalText.
Since ChineseText is child of OriginalText and EnglishTranslation is child of LanguageTranslation, the Translator class that uses wildcard extends allows to all classes <? extends OriginalText> to use Translator. By the same way for LanguageTranslation
EnglishTranslation
public class EnglishTranslation extends LanguageTranslation{
}
ChineseText
public class ChineseText extends OriginalText{
}
OriginalText
public class OriginalText {
}
LanguageTranslation
public class LanguageTranslation {
}
ChineseToEnglishTranslator
public class ChineseToEnglishTranslator extends Translator<ChineseText, EnglishTranslation> {
#Override
public EnglishTranslation translate(ChineseText originalText) {
return null;
}
}

Categories