Problem when trying to use generics - java

I have a class
public abstract class AbstractE<T, E extends Enum<E> & Flags>
{
public interface Flags{} /*marker interface*/
//...
//other code
}
and an interface
public interface IXYZAdapter
{
public <E extends Enum<E> & Flags> Set<E> getFlags();
}
Where Flags is an interface defined in AbstractE itself.
M extends AbstractE thus:
public class M extends AbstractE<Long, M.EF> implements IXYZAdapter
{
public enum EF implements AbstractE.Flags{flag1, flag2}
#Override /*from IXYZAdapter*/
public Set<M.EF> getFlags()
{return EnumSet.allOf(EF.class);}
}
Now, from the main code, I try to get a handle on the interface IXYZAdapter and invoke the getFlags method
IXYZAdapter adapter = (IXYZAdapter)m; //where m is an instance of AbstractE
Set s = adapter.getFlags();
I get the following compile time error in the main program last line (Set s = adapter.getFlags();)
invalid inferred types for E; inferred type does not conform to declared bound(s)
inferred: AbstractE.Flags
bound(s): java.lang.Enum<AbstractE.Flags>,AbstractE.Flags
What am I doing wrong?
I am using Java 6
Edited to specify the error location

Try this:
public interface IXYZAdapter <E extends Enum<E> & AbstractE.Flags>
{
public Set<E> getFlags();
}
And
public class M extends AbstractE<Long, M.EF> implements IXYZAdapter<M.EF>
{
}
Or
Set<M.EF> s = adapter.getFlags();
The problem is that with Set s = adapter.getFlags(); The system doesn't know which type to infer for E in IXYZAdapter and thus the E in AbstractE doesn't match.
Edit:
Another option might be:
interface IXYZAdapter <E extends Enum<E> & AbstractE.Flags>
{
public Set<? extends E> getFlags();
}
class M extends AbstractE<Long, M.EF> implements IXYZAdapter<M.EF>
{
public enum EF implements AbstractE.Flags{flag1, flag2}
public Set<? extends M.EF> getFlags()
{return EnumSet.allOf(EF.class);}
}
And the call: Set<? extends AbstractE.Flags> s = adapter.getFlags();
This would allow you to get a set of flags without casting and force the flags to be declared as enum.

using the first solution thomas provided, the main method can be written like this to become warning free without actually having to know about the enum type:
public static void main(String[] args) {
M m = new M();
IXYZAdapter<?> adapter = (IXYZAdapter<?>)m;
Set<?> flags = adapter.getFlags();
Iterator<?> it = flags.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}

Related

Generic interface and implementation - type cannot be converted

I have a generic interface defined as:
public interface ItemService<T extends Slicer, E extends ItemSlice> {
E getItemHistory(final String id, final T slicer);
}
And an implementation:
public class DynamoDbItemService implements ItemService<DynamoDbSlicer, DynamoDbItemSlice> {
public DynamoDbItemSlice getItemHistory(final String id, final DynamoDbSlicer slicer) {
}
}
Here are the definitions of the four classes referenced above:
public interface Slicer {
Map<String, ? extends Serializable> pointer();
}
public class DynamoDbSlicer implements Slicer {
public Map<String, AttributeValue> pointer() {
}
}
public interface ItemSlice extends Slice<Item> {
}
public interface Slice<T> {
List<T> data();
Slicer next();
}
public class DynamoDbItemSlice implements ItemSlice {
publi ImmutableList<Item> data() {}
public DynamoDbSlicer next() {}
}
I would like to reference the ItemService interface but for it to be bound to the DynamoDbItemService implementation so I can swap it out if necessary which I can do like so:
ItemService<? extends Slicer, ? extends ItemSlice> itemService = new DynamoDbItemService itemService();
but if I try to use itemService like this:
ItemSlice slice = itemService.getItemHistory(itemId, DynamoDbSlicer.first(1));
slice = itemService.getItemHistory(itemId, slice.next());
I get these two compilation errors:
Error:(231, 82) java: incompatible types: item.pagination.DynamoDbSlicer cannot be converted to capture#1 of ? extends pagination.Slicer
Error:(238, 62) java: incompatible types: pagination.Slicer cannot be converted to capture#2 of ? extends pagination.Slicer
I understand from this question that ? wildcards cannot be identical so my question is - can I do what I want - work with the interface? If so, how? Or am I approaching this incorrectly?
I have asked two previous questions related to this which have helped along the way (first and second)
I don't see a reason why the following wouldn't work for you:
ItemService<DynamoDbSlicer, DynamoDbItemSlice> itemService = new DynamoDbItemService();
ItemSlice slice = itemService.getItemHistory("", new DynamoDbSlicer());
But if you would like to make the code as modular as possible you can use this method to perform an unchecked cast (pure evil some say) and get the result you want:
public static void main(String[] args) {
ItemSlice slice = getMySlice(new DynamoDbItemService());
}
#SuppressWarnings("unchecked")
public static <T extends Slicer, E extends ItemSlice> E getMySlice(ItemService<T, E> service) {
return service.getItemHistory("", (T) new DynamoDbSlicer());
}
And then of course there is the solution of passing the type inference responsibility to the actual field that is storing the value. I myself would go for this solution, as I think it offers the most flexibility:
public class DynamoDbItemService<T extends Slicer, E extends ItemSlice> implements ItemService<T, E>
ItemService<DynamoDbSlicer, DynamoDbItemSlice> itemService = new DynamoDbItemService();
ItemSlice slice = itemService.getItemHistory("", new DynamoDbSlicer());

Incompatible types: inferred type does not conform to upper bound(s)

I was implementing some architecture when I saw the following error:
Error:(33, 55) java: incompatible types: inferred type does not conform to upper bound(s)
inferred: java.io.Serializable
upper bound(s): sandbox.ExpirePolicy,java.io.Serializable
The whole simplified code is below:
interface Configuration<K,V>{}
interface ExpirePolicy{}
interface Factory<T>{}
class FactoryBuilder {
public static <T extends Serializable> Factory<T> of(T instance){
System.out.println(instance.getClass());
return new Factory<T>() {};
}
}
class BaseConfiguration<K,V> implements Configuration<K,V> {
public BaseConfiguration<K,V> setExpiryPolicyFactory(Factory<? extends ExpirePolicy> factory){
return this;
}
}
class C<K,V> extends BaseConfiguration<K,V> {
public C<K,V> setExpiration(){
super.setExpiryPolicyFactory(FactoryBuilder.of((Serializable) getExpirePolicy()));
return this;
}
private ExpirePolicy getExpirePolicy(){
return new ExpirePolicy() {};
}
}
The exception is in trying to call setExpiryPolicyFactory(Factory<? extends ExpirePolicy> factory) with instance of Factory<Serializable>
But if i delete generic in extends BaseConfiguration<K,V> the program will be successfully compiled.
So the next declaration of class C is correct:
class C<K,V> extends BaseConfiguration {
public C<K,V> setExpiration(){
super.setExpiryPolicyFactory(FactoryBuilder.of((Serializable) getExpirePolicy()));
return this;
}
private ExpirePolicy getExpirePolicy(){
return new ExpirePolicy() {};
}
}
The question is: why the second implementation(of class C) will be successfully compiled and the first not?
UPD:
Simpler example of question (delete <T> from extends Base<T>) and program compiles well :
class Base<T> {
public void test(ArrayList<? extends CharSequence> list) {}
}
class Derived<T> extends Base<T> {
public void callTest() {
super.test(new ArrayList<Integer>());
}
}
When you delete <T> from extends Base<T> statement, the Base class starts to be treated as a raw type.
According to Java spec:
The supertype of a class may be a raw type. Member accesses for the
class are treated as normal, and member accesses for the supertype are
treated as for raw types. In the constructor of the class, calls to
super are treated as method calls on a raw type.
This means that super.test(...) call is also treated as method call on a raw type as if it has been declared like:
public void test(ArrayList list) {}
Thus no compilation errors happens.
It seems like the factory builder should take in an ExpirePolicy instead of Serializable for creating the factory. Changing the signature to
class FactoryBuilder {
public static <T extends ExpirePolicy> Factory<T> of(T instance){
System.out.println(instance.getClass());
return new Factory<T>() {};
}
}
enables using
class C<K,V> extends BaseConfiguration<K,V> {
public C<K,V> setExpiration(){
super.setExpiryPolicyFactory(FactoryBuilder.of(getExpirePolicy()));
return this;
}
private ExpirePolicy getExpirePolicy(){
return new ExpirePolicy() {};
}
}
without extra casts.
The second implementation of C compiles, but with warnings, because it's using raw types.

How to use wildcard generics with Sets.powerSet

I have some code like this
import com.google.common.collect.Sets;
public void handleInput(Set<Object> conditions){
Set<Set<Object>> powerSet = Sets.powerSet(conditions);
...
}
This works fine. But I want to do this:
public void handleInput(Set<? extends Object> conditions){
Set<Set<? extends Object>> powerSet = Sets.powerSet(conditions);
...
}
so I can get the powerset of objects that are subclasses of object. But this won't compile and I get the error:
Type mismatch: cannot convert from Set<Set<capture#1-of
? extends Object>> to Set<Set<? extends Object>>
How can I achieve this goal?
EDIT: I guess it has something to do with the generic type getting erased at compile time, so that the compiler can't know that powerSet won't add something illegal to the sets it's creating. I've reworked the client, by casting all the inputs to Object, and removing the wildcard altogether. Is this the best way? Thanks!
In this case it doesn't make any sense - since all Java classes extend java.lang.Object at some point.
So ? extends Object is redundant.
But speaking of Sets.powerSet, this works like a charm:
public class TestClass {
public static class A {}
public static class B extends A {}
public static class C extends B {}
public Set<? extends Set<? extends A>> exampleMethod(Set<? extends A> input) {
return Sets.powerSet(input);
}
public static void main(String[] args) {
final TestClass testClass = new TestClass();
final A a = new A();
final B b = new B();
final C c = new C();
System.out.println(
testClass.exampleMethod(
ImmutableSet.of(a, b, c)
)
);
}
}
as #slnowak notes, when you are extending Object, the code is really redundant.
However, to understand the Exception and avoid it...
public void handleInput(Set<? extends Object> conditions){
Set<? extends Set<? extends Object>> powerSet = Sets.powerSet(conditions);
...
}
this will compile and, more usefully, you can restrict the types in your conditions argument using this method, for instance - you could have:
public void handleInput(Set<? extends Number> conditions){
Set<? extends Set<? extends Number>> powerSet = Sets.powerSet(conditions);
...
}
and this would prevent you passing in sets that had non-numeric types and warn you of this at compile time.

Get actual enum class of the Parameterized class T extends Enum<?>

I have a class:
public class MultipleSorting<T extends Enum<?>> {
private T criteriaType;
public Class<T> getCriteriaClass() {
Field field = ReflectionUtils.getField(getClass(),"criteriaType");
ReflectionUtils.makeAccessible(field);
return (Class<T>)field.getType();
}
}
This class is get instantiated as:
public abstract class MultiSortPageableController<T extends MultiSortPageableController<?,?>, U extends Enum<?>> {
private MultipleSorting<U> multipleSorting;
public MultiSortPageableController() {
super();
multipleSorting = new MultipleSorting<U>();
}
}
The actual value of U is passed from the child class of MultiSortPageableController which is:
public abstract class AbstractArticleSearchController<T extends AbstractArticleSearchController<T>> extends MultiSortPageableController<T,ArticleSortField> {
}
The ArticleSortField is an Enum.
I was expecting the method getCriteriaClass of MultipleSorting would return ArticleSortField from a method of MultiSortPageableController. But it is returning java.lang.Enum.
I am unable to figure it out why it is not returning the actual enum and how can I make it so. Any pointer would be very helpful to me. I need to get ArticleSortField.
Purpose:
I two requirement:
To get the actual class of enum type (say ArticleSortField.class)
To list enum value. If I have the enum class, then I could invoke class..getEnumConstants().
Java compiler removes information about generics, therefore when you use reflection you get no information about the declared type, other than Enum. This process is called type erasure.
How about passing the type down, via the constructor, like this:
public class MultipleSorting<T extends Enum<?>> {
private Class<T> criteriaType;
MultipleSorting(Class<T> criteriaType) {
this.criteriaType = criteriaType;
}
public Class<T> getCriteriaClass() {
return criteriaType;
}
}
public abstract class MultiSortPageableController<T extends MultiSortPageableController<?, ?>, U extends Enum<?>> {
private MultipleSorting<U> multipleSorting;
public MultiSortPageableController(Class<U> criteriaType) {
super();
multipleSorting = new MultipleSorting<U>(criteriaType);
}
}
public abstract class AbstractArticleSearchController<T extends AbstractArticleSearchController<T>> extends MultiSortPageableController<T, ArticleSortField> {
public AbstractArticleSearchController() {
super(ArticleSortField.class);
}
}

How to convert implementors on one interface into another?

I'm having trouble finding a way to do this in a way that doesn't seem wrong, given the following
public interface IType {}
public interface IMode {}
public interface Factory<T extends IType> {
IMode get(T o);
Class<T> getIType();
}
I have the above interfaces and a large list on classes the implement both IType and IMode with corresponding factories.
I need to be able to convert from one to the other, for example,
public class A implements IType {}
public class One implements IMode {}
public class AToOne implements Factory<A> {
public IMode get(A o){
return new One();
}
public Class<A> getIType(){
return A.class;
}
}
Given that there is a 1 to 1 mapping of these classes, ie for every concrete IType there is one and only one concrete IMode with corresponding factory, how would I go about converting a list of ITypes to a list of IModes?
ie.
private List<Factory<? extends IType>> factoryList;
public List<IMode> getConversions(List<? extends IType> types){
???
}
My first try did not go so well,
//Fill this using the getIType() method from each factory
Map<Class<IType>, Factory<? extends IType>> factoryList = new HashMap<Class<IType>, Factory<? extends IType>>();
public List<IMode> getConversions(List<IType> types){
List<IMode> modes = new ArrayList<IMode>();
for(IType type : types){
//Derp
Factory<? extends IType> factory = factoryList.get(type.getClass());
//Error
factory.get(factory.getIType().cast(type));
}
}
Error:
The method get(capture#12-of ? extends IType) in the type
Factory<capture#12-of ? extends IType>
is not applicable for the arguments (capture#14-of ? extends IType)
Like I mentioned in my comment, you just need to use a generic helper method to access the map, which performs an unchecked cast from Factory<? extends IType> to a Factory<T> where T matches the type of what's passed in:
Map<Class<? extends IType>, Factory<? extends IType>> factoryList =
new HashMap<Class<? extends IType>, Factory<? extends IType>>();
private <T extends IType> IMode convert(T iType) {
//unchecked cast - implementation must guarantee map holds correct data
Factory<T> factory = (Factory<T>)factoryList.get(iType.getClass());
//then convert
return factory.get(iType);
}
You can call this helper method from the loop:
public List<IMode> getConversions(List<IType> types) {
List<IMode> modes = new ArrayList<IMode>(types.size());
for (IType type : types) {
IMode iMode = convert(type);
modes.add(iMode);
}
return modes;
}
The simple solution is the following:
interface IFoo {
}
interface IBar {
}
private static class Foo implements IFoo {
}
private static class Bar implements IBar {
}
interface IFoo2IBarConverter<B extends IBar, F extends IFoo> {
B convert(F foo);
}
private static class Foo2BarConverter implements IFoo2IBarConverter<Bar, Foo> {
public Bar convert(Foo foo) {
return new Bar();
}
}
private static class IFoo2IBarFactory {
private static HashMap<Class<? extends IFoo>, IFoo2IBarConverter<? extends IBar, ? extends IFoo>> converters = new HashMap<>();
static {
converters.put(Foo.class, new Foo2BarConverter());
}
public static<F extends IFoo, B extends IBar> B convert(F foo) {
// ugly unchecked cast here
IFoo2IBarConverter<B, F> converter = (IFoo2IBarConverter<B, F>) converters.get(foo.getClass());
return converter.convert(foo);
}
}
public static void main(String[] args) {
Foo foo = new Foo();
IBar bar = IFoo2IBarFactory.convert(foo);
}
You just take a HashMap that maps a specific class that's a subtype of IFoo to some converter interface. The converter takes the IFoo instance and converts it into a IBar.. actually into the specific classes we want. Sadly we get an ugly cast in IFoo2IBarFactory.convert() and I don't think there's any way to avoid that one. Still at least it's only in one localized position and with the right comment and a SuppressWarning you can live with it, I'd think

Categories

Resources