0

I am using an API with several operations to be performed, and it is currently under development. In order to isolate it, so I could deal easily with those constant changes, I've created a functional interface Operation with a method perform, like this:

public interface Operation<R, T> {
    R perform(T arg);
}

All operations I have implements this interface. For instance, the implementation of a find file action would be like this:

public class Finder implements Operation<InputStream, String> {
    @Override
    public InputStream perform(String arg) {
        //Code to find the file
    }
}

This class uses an InputStream as return and String as parameter, but other operations could take other parameters and have different returns...

To be able to create any operation, I've created an Enum called OperationType to identify each operation and a factory that creates those operations. The factory is below:

public class OperationsFactory {
    public static Operation create(OperationType type) {
        switch (type) {
        case FIND:
            return new Finder();
        // cases for each operation
        default:
            throw new InvalidParameterException("Can't create operation type: " + type.toString());

        }
    }
}

Ok, this is the structure I have. It might not be the best option for you, but that's not the problem I'm trying to solve here. The thing is, when I try to use it I get Unchecked Assignment warning, and I want to remove it without putting an annotation to ignore such warning (which is bad, in my opinion). Let me put a code of a method that would have this exception:

public InputStream performFindOperation(String path) {
    Operation<InputStream, String> findOperation = OperationsFactory.create(OperationType.FIND); //warning here!!
    return findOperation.perform(path);
}

So, Java experts, how do I remove this warning?

Gale
  • 215
  • 3
  • 15
Leonardo Alves Machado
  • 2,747
  • 10
  • 38
  • 53
  • The question someone put as duplicate explains raw types, but does not address how to avoid the warnings I'm getting (and, by its title and content, it shouldn't). Anyway, Oleg Pyzhcov's answer did the trick for me – Leonardo Alves Machado Dec 05 '19 at 14:47

2 Answers2

1

It's because your OperationsFactory returns an Operation rather than a properly genericized Operation<X, Y>, so if you assign it to findOperation of type Operation<InputStream, String>, you get this warning (because the compiler can't assure you assign the right type).

Sadly, you can't add generics to enums (it's on a future Java feature list), so you won't be able to safely do that. The only way to get rid of the warning is to suppress it.

As a side note, you could just use a java.util.Function<T, R> rather than defining your own functional interface.

daniu
  • 14,137
  • 4
  • 32
  • 53
1

Notice the absence of type parameters here:

public static Operation create(OperationType type) {
//                    ^ isn't something supposed to be there?

This is known as raw type, and is effectively equivalent with Operation<Object, Object>, however, it can be assigned to Operation<A, B> for any A and B.

What language is pushing you to do with this warning is to specify the actual type of returned operation, e.g.:

public static Operation<InputStream, String> create(OperationType type) {

Raw types should be avoided in modern code, they exist for historical backwards compat reasons (Java did not have generics prior to version 5).


EDIT: Actually, what you want to do requires quite advanced type system with some support for dependent types that Java does not have - if you want to avoid a warning, that is. I recommend you to enumerate the options as plain fields instead of trying to use a standard enum, e.g.

public class OperationType {
  public static Operation<InputStream, String> FIND = ...
  public static Operation<OutputStream, String> WRITE = ...
  ...
}
Oleg Pyzhcov
  • 7,323
  • 1
  • 18
  • 30