Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - Is it safe to suppress unchecked cast warning with WatchEvent?

I have the following test code:

FileSystem fs = FileSystems.getDefault();
Path conf = fs.getPath(".");
WatchKey key = null;
try {
    WatchService watcher = fs.newWatchService();
    conf.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
    while(true) {
        key = watcher.take(); // waits
        for (WatchEvent<?> event : key.pollEvents()) {

            WatchEvent.Kind<?> kind = event.kind();
            if (StandardWatchEventKinds.OVERFLOW == kind) continue;
        
            WatchEvent<Path> ev = (WatchEvent<Path>)event;
            Path file = ev.context();
            System.out.println(file);
        }
    }
} catch (IOException | InterruptedException e) {
    throw new RuntimeException(e.getMessage(), e);
}

The compiler issues an unchecked cast warning related to the line

WatchEvent<Path> ev = (WatchEvent<Path>)event;

since event comes out of key.pollEvents() as a WatchEvent<?>, and the compiler can't tell if during runtime it's really going to contain a Path, and not something else.

Regarding this, I was wondering if it's possible to get rid of this warning without explicitly suppressing it. I found some hint, although related to quite different situations, like this, but here it seems that they can control how the generic list is built, while in my case this isn't possible.

I also found this, where they suggest to suppress the warning, checking at the same time if the actual type is the correct one (since the compiler can't do it on its own), but I couldn't manage to do something along these lines in my case. Is it possible? How would you do it?

On the other hand, in my case I'm getting these WatchEvent's from a WatchService registered with a Path object: is this fact alone enough to prove that every WatchEvent<?> coming out from this WatchService<?> will have a Path type implementation? If this is true, can I safely assume that the cast will always be correct and suppress the warning? Is there any way to avoid it without suppressing it in this case?

Thank you very much.

EDIT

I could have immediately checked the references that explicitly state that:

T context()

Returns the context for the event.

In the case of ENTRY_CREATE, ENTRY_DELETE, and ENTRY_MODIFY events the context is a Path that is the relative path between the directory registered with the watch service, and the entry that is created, deleted, or modified.

So in my case I'm watching for ENTRY_MODIFY events, hence my T type is definetely a Path.

like image 764
swahnee Avatar asked May 11 '15 20:05

swahnee


People also ask

How can I avoid unchecked cast warnings?

If we can't eliminate the “unchecked cast” warning and we're sure that the code provoking the warning is typesafe, we can suppress the warning using the SuppressWarnings(“unchecked”) annotation. When we use the @SuppressWarning(“unchecked”) annotation, we should always put it on the smallest scope possible.

What is suppress warning unchecked?

In other words, it basically, tells a programmer that a cast may cause a program to throw an exception somewhere else. Suppressing the warning with @SuppressWarnings("unchecked") tells the compiler that the programmer believes the code to be safe and won't cause unexpected exceptions.

What does unchecked cast mean Java?

Unchecked cast means that you are (implicitly or explicitly) casting from a generic type to a nonqualified type or the other way around.


1 Answers

I think the best option is to just suppress it

            @SuppressWarnings("unchecked")
            WatchEvent<Path> ev = (WatchEvent<Path>)event;

it's perfectly safe, it can only be <Path> and nothing else. The API designer went a little crazy of being too general.

WatchService is kind of difficult to use. I have the following utility class you might be intereted in

https://github.com/zhong-j-yu/bayou/blob/0.9/src/_bayou/_tmp/_FileMonitor.java

For example

_FileMonitor monitor = new _FileMonitor( ROOT_DIR );

List<Set<Path>> changes = monitor.pollFileChanges( TIMEOUT )
// return 3 sets, [0]=created, [1]=modified, [2]=deleted
like image 93
ZhongYu Avatar answered Oct 21 '22 00:10

ZhongYu