I've got an issue with a generic framework I'm writing.
Can someone explain to me, why my code does not compile? I've tried to show it with this simple example. (UPDATED EXAMPLE)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
public class TestGeneric {
public static void main(String... sss) throws Exception {
Dao dao = new Dao("Hello");
dao.extend();
System.out.println(dao.getHelloWorld());
}
}
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
#interface TestAnnotation {
public Class<? extends AbstractCommand<? extends AbstractDao>>[] commands() default {};
}
abstract class AbstractDao {
public void extend() throws Exception {
for (Field field : this.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(TestAnnotation.class)) {
TestAnnotation annotation = field.getAnnotation(TestAnnotation.class);
for (Class<? extends AbstractCommand<? extends AbstractDao>> commandClass : annotation.commands()) {
AbstractCommand<? extends AbstractDao> command = commandClass.newInstance();
command.doSomething(this);
}
}
}
}
}
class Dao extends AbstractDao {
#TestAnnotation(commands = { Command.class })
private String hello;
private String world;
public Dao(String hello) {
this.hello = hello;
}
public String getHello() {
return this.hello;
}
public void setWorld(String world) {
this.world = world;
}
public String getHelloWorld() {
return this.hello + " " + this.world;
}
}
abstract class AbstractCommand<T extends AbstractDao> {
public abstract void doSomething(T t);
}
class Command extends AbstractCommand<Dao> {
#Override
public void doSomething(Dao t) {
if (t.getHello().equals("Hello")) {
t.setWorld("World");
}
}
}
As soon as I make following changes ...
abstract class AbstractCommand<T extends AbstractDao> {
public abstract void print(AbstractDao t);
}
class Command extends AbstractCommand<Dao> {
#Override
public void doSomething(AbstractDao t) {
Dao dao = (Dao) t;
if (dao.getHello().equals("Hello")) {
dao.setWorld("World");
}
}
}
... everything works fine, but then I have to cast AbstractDao all the time.
As far as I can say, everything should be save, but I keep getting this error.
The method print(capture#3-of ? extends AbstractDao) in the type AbstractCommand is not applicable for the arguments (Dao)
But Dao extends AbstractDao, so where exactly is the problem?
I already found this question generics error: not applicable for the arguments but I'm not sure whether or not it is the same problem I have.
My guess is that it has something to do with 'Because the Java compiler erases all type parameters in generic code, you cannot verify which parameterized type for a generic type is being used at runtime'
Does anyone have a solution for this problem?
Thanks!
You're using an AbstractCommand reference.
Try this
((Command)command).print(new Dao("Hello World"));
Related
I have the following scenario:
public abstract class BaseTask{...}
public class TaskA extends BaseTask {....}
public class TaskB extends BaseTask {....}
public interface TaskService<T extends BaseTask>{
void process(T task);
}
#Service #Qualifier("taskServiceA")
public class TaskServiceA<TaskA> implements TaskService<TaskA>{
}
#Service #Qualifier("taskServiceB")
public class TaskServiceB<TaskB> implements TaskService<TaskB>{
}
public class ProcessingService{
#Autowired #Qualifier("taskServiceA")
private TaskService<TaskA> taskAService;
#Autowired #Qualifier("taskServiceB")
private TaskService<TaskB> taskBService;
public void process(Order o){
BaseTask task = o.getTask();
getTaskService(o).start(task);
}
private <T extends BaseTask> TaskService<T> getTaskService(Order o){
if("atype".equals(o.type)){
return (TaskService<T>) taskAService;
} else if("btype".equals(o.type)){
return (TaskService<T>) taskBService;
}
}
}
Update: I have reworded the question because the answers I was getting was not what I was looking for.
My questions is related to the getTaskService method.
Why do I need to cast the return value like this
return (TaskService) taskAService;
Is there another way to implement the getTaskService() method without having to do the cast?
I will really appreciate if someone can provide some explanation or better implementation for the getTaskService method.
How about this?
No need of any if conditions.
Later if someone does add another implementation of BaseTask they don't have to change any other code.
Also I recommend changing "atype" to Enum and using Map<EnumTask, ? extends BaseTask> serviceMap; instead of String.
Your final invocation of Tasks can be without any checks
#Service
class ProcessingService {
#Autowired
private TaskServiceManager taskServiceManager;
public void process(Order o){
taskServiceManager.getServiceTask(o.type).start(task);
}
}
Other classes
enum ServiceEnum {
TaskA,
TaskB
}
public class TaskA extends BaseTask {....}
public class TaskB extends BaseTask {....}
public abstract class TaskService<T extends BaseTask>{
public TaskService(ServiceEnum serviceEnum, TaskServiceManager taskServiceManager) {
taskServiceManager.registerTask(serviceEnum, this);
}
void process(T task);
}
#Service #Qualifier("taskServiceA")
public class TaskServiceA<TaskA> implements TaskService<TaskA>{
#Autowired
public TaskA(TaskServiceManager taskServiceManager) {
super(ServiceEnum.TaskA, taskServiceManager);
}
}
#Service #Qualifier("taskServiceB")
public class TaskServiceB<TaskB> implements TaskService<TaskB>{...}
#Service
class TaskServiceManager {
Map<ServiceEnum, ? extends TaskService> serviceMap;
public <T extends TaskService> void registerTask(ServiceEnum serviceName, T task) {
if(serviceMap.containsKey(serviceName)) {
throw new IllegalArgumentException("ServiceName is already in the Map");
}
serviceMap.put(serviceName, task);
}
public <T extends TaskService> T getServiceTask(ServiceEnum serviceName) {
if(!serviceMap.containsKey(serviceName)) {
throw new IllegalArgumentException("ServiceName is not Registered");
}
return serviceMap.get(serviceName);
}
}
Because type T is resolved wherever the method is used. The following statement is valid:
TaskService<TaskA> s = getTaskService(o);
So is:
TaskService<TaskB> s = getTaskService(o);
So within the method getTaskService, you don't know much about T.
The correct way to do this would be:
private TaskService<? extends BaseTask> getTaskService(Order o) {
if ("atype".equals(o.type)) {
return taskAService;
} else if ("btype".equals(o.type)) {
return taskBService;
} else {
return null;
}
}
The assignment above would have to become:
TaskService<? extends BaseTask> s = getTaskService(o);
I'm developing a database application for android devices.
First thing I need to do is creating the data access layer.
For this I want to use DAO-Pattern with abstract factories.
For all DAOs i have one Interface witch contains the declaration that all data object needs to implement. (in my case: IDataObject)
The specific DAOs are all represented by its own interface, extending the base interface of all DAOs.
base interface:
public interface IDataObject {
public IDataId getId();
public void write() throws MyDataWriteException;
public void validate() throws MyDataValidException;
}
a extensions:
public interface IDataSample1 extends IDataObject {
public void setNotice(String notice);
public String getNotice();
public void setDate(Date date);
public Date getDate();
}
To create an data object I want use abstract to use abstract factories, something like:
public interface IDataFactory<Template extends IDataObject> {
public List<Template> getAll();
public Template get(IDataId id);
public List<Template> getList(DataAccessArgument arg);
public List<Template> getList(List<DataAccessArgument> argList);
}
and the implementation:
public class DataSample1Fac implements IDataFactory<IDataSample1> {
public DataSample1Fac () {
}
public List<IDataSample1> getAll() {
return null;
}
public IDataSample1 get(IDataId id) {
return null;
}
public List<IDataSample1> getList(DataAccessArgument arg) {
return null;
}
public List<IDataSample1> getList(List<DataAccessArgument> argList) {
return null;
}
}
I don't get any error so far, but now I want to implement an factory builder:
public class DataFactoryBuilder {
private DataFactoryBuilder() {
}
public static<T extends IDataObject> IDataFactory<T> getFactory(){
if (T instanceof IDataSample1)
return new DataSample1Fac();
return null;
}
}
I get following errors(line 8):
T cannot be resolved to a variable
and (line 9)
Type mismatch: cannot convert from DataSample1Fac to IDataFactory<T>
Don't know how to fix this, any suggestions?
I would refactor Your's DataFactoryBuilder to something like that:
class DataFactoryBuilder {
private DataFactoryBuilder() {
}
public static IDataFactory<? extends IDataObject> getFactory(Class<? extends IDataObject> clazz){
if (IDataSample1.class.isAssignableFrom(clazz)) {
return new DataSample1Fac();
}
return null;
}
}
I got following solution:
public static <T extends IDataObject> IDataFactory<T> getFactory(Class<T> type) {
if (IDataSample1.class.isAssignableFrom(type)) {
DataSample1Facfac = new DataSample1Fac();
return (IDataFactory<T>) fac;
}
}
but i get an warning on: return (IDataFactory) fac;
Type safety: Unchecked cast from DataSample1Fac to IDataFactory<T>
I think that is not a problem, I just have to supress it
Please help resolve an issue regarding generics. I tried many ways but it's still not working.
Problem is:
public static void main(String[] args) {
Utils.execute(new TestAction(), new TestCallBack());
}
Compiler show error:
The method execute(Action<?>, CallBack<?,Action<?>>) in the type Utils is not applicable for the arguments (ImplementClass.TestAction, ImplementClass.TestCallBack)
My classes is:
Action class:
public abstract class Action<R> {
public R getResult() {
return null;
}
}
TestAction class is:
class TestAction extends Action<String> {
#Override
public String getResult() {
return super.getResult();
}
}
Callback class is:
public interface CallBack<R, A extends Action<R>> {
public void onCall(A action);}
TestCallback class is:
class TestCallBack implements CallBack<String, TestAction> {
#Override
public void onCall(TestAction action) {
}
}
And Utils class is:
public class Utils {
public static void execute(Action<?> action, CallBack<?, Action<?>> callback) {
}
}
Thanks a lot.
The second parameter of the execute method is CallBack<?, Action<?>>, and Action there means the Action class itself, subclass of it is not allowed. What you need there is - ? extends Action<?>, which means either Action or some subclass of it.
Try changing the method signature -
public static void execute(Action<?> action, CallBack<?, ? extends Action<?>> callback) {
Note:
Generics are not co-variant. Take for example a method as follows -
static void method(List<Object> l) {}
And an invocation as follows is not allowed -
method(new ArrayList<String>());
You need to change two things,
TestCallBack should be like this -
public static class TestCallBack implements CallBack<String, Action<String>> {
#Override
public void onCall(Action<String> action) {
}
}
and, Utils should be like this -
public static class Utils {
// You need to ensure the same type, not just try and accept anything.
public static <T> void execute(Action<T> action, CallBack<?, Action<T>> callback) {
}
}
or using inner classes of a class called Question -
public abstract class Action<R> {
public R getResult() {
return null;
}
}
public class TestAction extends Action<String> {
#Override
public String getResult() {
return super.getResult();
}
}
public interface CallBack<R, A extends Action<R>> {
public void onCall(A action);
}
public class TestCallBack implements CallBack<String, TestAction> {
#Override
public void onCall(TestAction action) {
}
}
public class Utils {
public void execute(Action<?> action, CallBack<?, ? extends Action<?>> callback) {
}
}
public static void main(String[] args) {
Question question = new Question();
question.new Utils().execute(question.new TestAction(), question.new TestCallBack());
}
I had an interface initially as below.
public interface testMe {
public Set<String> doSomething();
}
public class A implements testMe {
public Set<String> doSomething() {
return // Set<String>
}
}
I had similar classes implementing testMe. Now I have to add one more class which returns Set<Some Object>
public class X implements testMe() {
public Set<Some OBject> doSomething() {
}
}
How could i add this method in the interface without breaking existing classes?
You can use
public interface testMe {
public Set<?> doSomething();
}
Or
public interface testMe {
public Set<? extends CommonSuperclass> doSomething();
}
You can't for two reasons.
A class or interface can't have two or more methods that have the same number and type of parameters with the same name but differing return types; and
Because of type erasure, all Set<...> instances are, at runtime, simply Set, so they would have the exact same return type anyway.
You will need to name the second something different.
The more complicated answer is that you can make the parameter type extensible:
public interface TestMe<T extends Serializable> {
Set<T> doSomething();
}
public class A implements TestMe<String> {
#Override
public Set<String> doSomething() { ... }
}
public class X implements TestMe<ASerializableObject> {
#Override
public Set<ASerializableObject> doSomething() { ... }
}
I don't believe you can, because type erasure will ruin the effect you have in mind.
You can parameterize the interface:
import java.util.Set;
public interface ISomething<T>
{
Set<T> doSomething(T [] data);
}
And the implementation:
import java.util.HashSet;
import java.util.Set;
public class Something<T> implements ISomething<T>
{
public static void main(String[] args)
{
Something<String> something = new Something<String>();
Set<String> set = something.doSomething(args);
System.out.println(set);
}
public Set<T> doSomething(T [] data)
{
Set<T> foo = new HashSet<T>();
for (T x : data)
{
foo.add(x);
}
return foo;
}
}
I'm not sure this accomplishes what you have in mind, though.
I have following class, I need to get type in constructor, how can I do that?
public abstract class MyClass<T> {
public MyClass()
{
// I need T type here ...
}
}
EDIT:
Here is concrete example what I want to achieve:
public abstract class Dao<T> {
public void save(GoogleAppEngineEntity entity)
{
// save entity to datastore here
}
public GoogleAppEngineEntity getEntityById(Long id)
{
// return entity of class T, how can I do that ??
}
}
What I want to do is to have this class extended to all other DAOs, because other DAOs have some queries that are specific to those daos and cannot be general, but these simple queries should be generally available to all DAO interfaces/implementations...
You can get it, to some degree... not sure if this is useful:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
abstract class MyClass<T> {
public MyClass() {
Type genericSuperclass = this.getClass().getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericSuperclass;
Type type = pt.getActualTypeArguments()[0];
System.out.println(type); // prints class java.lang.String for FooClass
}
}
}
public class FooClass extends MyClass<String> {
public FooClass() {
super();
}
public static void main(String[] args) {
new FooClass();
}
}
We've done this
public abstract BaseClass<T>{
protected Class<? extends T> clazz;
public BaseClass(Class<? extends T> theClass)
{
this.clazz = theClass;
}
...
}
And in the subclasses,
public class SubClass extends BaseClass<Foo>{
public SubClass(){
super(Foo.class);
}
}
And you cannot simply add a constructor parameter?
public abstract class MyClass<T> {
public MyClass(Class<T> type) {
// do something with type?
}
}
If I'm not reading this wrong, wouldn't you just want
public <T> void save(T entity)
and
public <T> T getEntityById(Long id)
for your method signatures?