简体   繁体   中英

How can pass my class to the generic specification of the class?

I have the following method signature

public abstract class AbstractFilterParametersWithSpecificationSorting<T> extends AbstractFilterParameters
...

public void registerOrderSpecification( final String key, final Class<? extends OrderSpecification<T>> spec ) {
...

I'm passing the following

    this.registerOrderSpecification(
            AbstractActivityLogWithSiteUser.Index.USER_FULL_NAME,
            SortActivityLogUserOrderSpecification.class );

which has this class definition

public class SortActivityLogUserOrderSpecification<AL extends AbstractActivityLogWithSiteUser<?>>
    extends AbstractOrderSpecification<AL> implements OrderSpecification<AL>

here's what javac doesn't like (IDEA thinks it should work, but IDEA is running on Java 8, and the code must compile on Java 7)

Error:(12, 21) java: method registerOrderSpecification in class com.myapp.service.principal.AbstractFilterParametersWithSpecificationSorting<T> cannot be applied to given types;
required: java.lang.String,java.lang.Class<? extends com.myapp.specification.OrderSpecification<AL>>
found: java.lang.String,java.lang.Class<com.myapp.repository.activitylog.specification.SortActivityLogUserOrderSpecification>
reason: actual argument java.lang.Class<com.myapp.repository.activitylog.specification.SortActivityLogUserOrderSpecification> cannot be converted to java.lang.Class<? extends com.myapp.specification.OrderSpecification<AL>> by method invocation conversion

can I cast it? or am I missing some question mark somewhere?

I tried your code and then started simplifying it to get to a smaller example that showed the same problem. I finally got to this (much simpler) code:

abstract class MyList<T> implements java.util.List<T> {
}

public class TestGenerics2<T> {

    public void processListClass(final Class<? extends java.util.List<T>> spec ) {
    }

    public void tryIt() {
        this.processListClass(MyList.class);
    }

}

Generates this error:

TestGenerics2.java:11: processListClass(java.lang.Class<? extends java.util.List<T>>) in TestGenerics2<T> cannot be applied to (java.lang.Class<MyList>)

I think you should cast it (or refactor your code so that you don't need that generic's complexity).

Like Jon Skeet once said :

Sometimes Java generics just doesn't let you do what you want to, and you need to effectively tell the compiler that what you're doing really will be legal at execution time.

So my answer is inspired by remembering the complaint that spawned the diamond <> operator in Java 7, and that support was improved in 8.

Why should you write

List<Foo> foos = new ArrayList<Foo>();

when

List<Foo> foos = Lists.newArrayList();

will just work. This of course spawned the diamond operator

List<Foo> foos = new ArrayList<>();

so I wrote a method to wrap my class parameter

protected <E extends OrderSpecification<T>> Class<E> java7classReturnType( Class<E> clazz ) {
    return clazz;
}

and calling this will work fine

Class<? extends OrderSpecification<OrganizationActivityLog>> clazz
            = this.java7classReturnType( SortActivityLogUserOrderSpecification.class );
    this.registerOrderSpecification( AbstractActivityLogWithSiteUser.Index.USER_FULL_NAME, clazz );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM