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.
Related
I have a set of classes that extend a generic class. This class in turn implements an interface.
I want to be able to instantiate the objects that extent this class based on some string value, using reflection.
Interface
public interface Vehicle {
public String reportStats();
}
Generic Class
public class Premium implements Vehicle {
public String reportStats() {
return "generic stats";
}
}
One type
public class Volvo extends Premium {
public void drive() {
// impl
}
}
Another type
public class Mercedez extends Premium {
public void drive() {
// impl
}
}
Trying to instantiate using reflection
String objectStr = "org.test.project.impl.Volvo";
Class<? extends Vehicle> vehicleClass;
vehicleClass = (Class<? extends Vehicle>) Class.forName(objectStr);
// this does not work
// the error that i get is Volvo cannot be casted to Vehicle
Vehicle vehicle = vehicleClass.cast(vehicleClass.newInstance());
String stats = vehicle.reportStats();
This appears to be working if the classes are in the same jar, but if Mercedez or Volvo are factored out into a separate jar, under the same package, the cast fails with a java.lang.ClassCastException.
Thanks.
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>>{
I have written a converter structure in Java for which I'd like to create a factory.
My basic idea is that I pass in a class of a valid type and receive a valid subtype converter but fail with the generics and inheritance part.
This is my interface:
interface ItemRequestConverterFactory {
public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(Class<IR> clazz);
}
and the implementation:
public class DefaultItemRequestConverterFactory implements ItemRequestConverterFactory {
#Override
public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(Class<IR> clazz) {
if (clazz.equals(CreatePartRequestConverter.class))
return new CreatePartRequestConverter();
return null;
}
}
Unfortunately, Eclipse says: "Type mismatch: cannot convert from CreatePartRequestConverter to ItemRequestConverter".
Where is the problem in my generic signature?
You seem to have a mismatch between the type parameters and the types that they should actually represent: You are passing a Class<IR> to the newInstance method. This is a class that represents an ItemRequest. However, you are comparing this class instance to a class that is probably an implementation of the ItemRequestConverter interface.
Although this compiles when you add an appropriate type parameter to the CreatePartRequestConverter class, it's probably not what you want to achieve:
interface ItemRequestConverter<IR extends ItemRequest>{}
interface ItemRequest{}
interface ItemRequestConverterFactory
{
public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(Class<IR> itemRequestClass);
}
class CreatePartRequestConverter<IR extends ItemRequest> implements ItemRequestConverter<IR>
{
}
class DefaultItemRequestConverterFactory implements ItemRequestConverterFactory
{
#Override
public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(Class<IR> itemRequestClass)
{
// Does not make sense: Comparing ItemRequest class with something
// that is probably an implementation of ItemRequestConverter
if (itemRequestClass.equals(CreatePartRequestConverter.class))
{
return new CreatePartRequestConverter<IR>();
}
return null;
}
}
Depending on what you actually want to achieve, you could pass the ItemRequestConverter class to the factory method (and parameterize the method accordingly) :
interface ItemRequestConverter<IR extends ItemRequest>{}
interface ItemRequest{}
interface ItemRequestConverterFactory
{
public <IRC extends ItemRequestConverter<?>> ItemRequestConverter<?> newInstance(Class<IRC> itemRequestConverterClass);
}
class CreatePartRequestConverter implements ItemRequestConverter<ItemRequest>
{
}
class DefaultItemRequestConverterFactory implements ItemRequestConverterFactory
{
#Override
public <IRC extends ItemRequestConverter<?>> ItemRequestConverter<?> newInstance(
Class<IRC> itemRequestConverterClass)
{
if (itemRequestConverterClass.equals(CreatePartRequestConverter.class))
{
return new CreatePartRequestConverter();
}
return null;
}
}
If you also need the information about the ItemRequest class, the method signatures may start to become a little bit nasty, and one would have to analyze in more detail where and how this type information should be provided or used.
EDIT for the comment:
I think that this is not possible in a (compile-time) type-checked way. The problem here is that at the point where you create and return the new ItemRequestConverter, you can not say for sure that it is an ItemRequestConverter whose type parameter is IR. Or the other way around: You can't detect at compile-time that the type parameter of CreatePartRequestConverter (namely, CreatePartRequest) is the same as IR.
Based on the code snippets discussed so far, I think that it should be possible to simply cast in this case. The responsibility of making sure that the cast is valid is then left to the one who implements the "runtime-type-check":
if (itemRequestClass.equals(CreatePartRequest.class))
{
CreatePartRequestConverter result = new CreatePartRequestConverter();
return (ItemRequestConverter<IR>) result;
}
because nothing prevents you from writing
// !!!
if (itemRequestClass.equals(SomeCompletelyDifferentRequest.class))
{
CreatePartRequestConverter result = new CreatePartRequestConverter();
return (ItemRequestConverter<IR>) result;
}
So it should be valid to do this:
interface ItemRequestConverter<IR extends ItemRequest>{}
interface ItemRequest{}
interface ItemRequestConverterFactory
{
public <IR extends ItemRequest> ItemRequestConverter<IR>
newInstance(Class<IR> itemRequestClass);
}
class CreatePartRequest implements ItemRequest {}
class CreatePartRequestConverter
implements ItemRequestConverter<CreatePartRequest> {}
class DefaultItemRequestConverterFactory implements ItemRequestConverterFactory
{
#Override
public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(
Class<IR> itemRequestClass)
{
if (itemRequestClass.equals(CreatePartRequest.class))
{
CreatePartRequestConverter result = new CreatePartRequestConverter();
return (ItemRequestConverter<IR>) result;
}
return null;
}
}
public class GenericFactoryTest
{
public static void main(String[] args)
{
ItemRequestConverterFactory factory = null;
ItemRequestConverter<CreatePartRequest> converter =
factory.newInstance(CreatePartRequest.class);
}
}
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);
}
...
I'm studying Java Generic type.
I have the abstract class AbstractInputdata.
public abstract class AbstractInputData {
....
}
Some class that extend AbstractInputData
public class Email extends AbstractInputData{
...
}
public class Mobile extends AbstractInputData{
...
}
......
A.
public class ProcessorA {
public static boolean isCustomData(AbstractInputData abstractInputData) {
....
}
}
B.
public class ProcessorB {
public static <T extends AbstractInputData> boolean isCustomData(T t) {
...
}
}
Is there any difference between A and B?
The only difference is that the second method with appear as a generic typed method via Reflections. It's behaviour will be the same except in odd cases like this
processorB.<MyType>isCustomData(t); // won't compile unless t is a MyType
You would have to tell it what type you expect it to match, which isn't that useful IMHO.
Since your methods only produce a boolean, there is no difference. But in case you want to return the input you can use B to preserve the generic type:
public class ProcessorB {
public static <T extends AbstractInputData> boolean isCustomData(T t) {
...
}
public static <T extends AbstractInputData> T copyCustomData(T t) {
...
}
}
ProcessorA could only return an object of type AbstractInputData while processorB returns Email or Mobile depending on the parameter type.