GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Bug in generics architecture: FileHandle<FileLocation> is not DataHandle<Location> · Issue #469 · scijava/scijava-common

Bug in generics architecture: FileHandle<FileLocation> is not DataHandle<Location> #469

New issue
Copy link
New issue
Copy link
Open
Open
Bug in generics architecture: FileHandle<FileLocation> is not DataHandle<Location>#469
Copy link

Description

@Daniel-Alievsky
Daniel-Alievsky
opened on Aug 7, 2023
Issue body actions

This issue is connected with #468

Below is a very simple test, using SCIFIO TiffParser:

public class FileHandleGenericsBug {
    public static void main(String[] args) {
        if (args.length < 1) {
            System.out.println("Usage:");
            System.out.println("    " + FileHandleGenericsBug.class.getName() + " some_tiff_file");
            return;
        }
        final File file = new File(args[0]);

        Context context = new SCIFIO().getContext();
        TiffParser parser = new TiffParser(context, new FileLocation(file));
        DataHandle<Location> stream = parser.getStream();
        System.out.println("Successfully opened: " + stream.getLocation());

        BytesLocation bytesLocation = new BytesLocation(1000);
        stream.set(bytesLocation); // - crash!! java.lang.ClassCastException

        System.out.println("This operator will not be performed");
        context.close();
    }
}

TiffParser input stream, as well as some analogous streams in other classes, is declared as DataHandle<Location>. But really it is not a sub-type of DataHandle<Location>! In terms of Java generics, it is DataHandle<? extends Location>

Unfortunately, DataHandle is implemented as a container, that can store an object of the generic type, i.e. Location, alike in classes List, Set etc. In other words, it has a method
void set(Location loc);
It means that we can pass to this method any Location subclass, for example, BytesLocation. As a result, a simple call "stream.set(bytesLocation)" in the code above throws ClassCastException.

Of course, the compiler tries to warn about the problem, but you suppress the warning inside the method PluginInfo.loadClass:

	public Class<? extends PT> loadClass() throws InstantiableException {
		if (pluginClass == null) {
			try {
				final Class<?> c = Types.load(className, classLoader, false);
				@SuppressWarnings("unchecked")
				final Class<? extends PT> typedClass = (Class<? extends PT>) c;
				pluginClass = typedClass;
			}
			catch (final IllegalArgumentException exc) {
				throw new InstantiableException("Class not found: " + className, exc);
			}
		}

		return pluginClass;
	}

FileHandle class "supports" FileLocation, so, it is created without exceptions, though actually FileHandle is not DataHandle<Location>

Of course, the same problem appears when I try to create DataHandle<Location> with help of my own function:

    /**
     * Warning: you should never call {@link DataHandle#set(Object)} method of the returned result!
     */
    @SuppressWarnings("rawtypes, unchecked")
    public static DataHandle<Location> getFileHandle(FileLocation fileLocation) {
        Objects.requireNonNull(fileLocation, "Null fileLocation");
        FileHandle fileHandle = new FileHandle();
        fileHandle.set(fileLocation);
        return (DataHandle) fileHandle;
    }

The problem is essentially serious. Unfortunately, TiffParser, like many other classes based on DataHandle technique, declare the streams as DataHandle<Location>, and it is a public declaration (for example, result of TiffParser.getStream() method is used in TIFFFormat class). I'm afraid you cannot just to replace DataHandle<Location> with correct and safe DataHandle<? extends Location> - a lot of client will stop be compiled.

But, maybe, you can rework the class FileHandle (and BytesHandle, and other known implementations of DataHandle) to reduce the problem? I've tried to do this with FileHandle - see the attached file. Now it extends AbstractDataHandle<Location>, not AbstractDataHandle<FileLocation>. I've added "main" test method to illustrate an idea: now "set" method works with Location instead of FileLocation, but it checks the type of the argument itself. However, I don't know how to correctly change the method getType() - it seems it will become a problem...

In any case, please think over the problem. Maybe you will find better solution.

FileHandle.zip

Activity

  1. Daniel-Alievsky
    changed the title [-]Bug in generitcs arthitecture: FileHandle<FileLocation> is not DataHandle<Location>[/-] [+]Bug in generics arthitecture: FileHandle<FileLocation> is not DataHandle<Location>[/+] on Aug 7, 2023
  2. Daniel-Alievsky
    added a commit that references this issue on Aug 7, 2023

    TiffTools: unsafe method of creating DataHandle<Location> became pack…

    06329d3
  3. Daniel-Alievsky commented on Aug 7, 2023

    @Daniel-Alievsky
    Daniel-Alievsky
    on Aug 7, 2023
    Author
    More actions

    Also note: according common Java agreements, DataHandle<Location> public type of the method result seems to be better than DataHandle<? extends Location> If possible, we should prefer more simple generic types in API, and it is an argument in favor of reworking FileHandle to a subclass of AbstractDataHandle<Location>

  4. Daniel-Alievsky
    changed the title [-]Bug in generics arthitecture: FileHandle<FileLocation> is not DataHandle<Location>[/-] [+]Bug in generics architecture: FileHandle<FileLocation> is not DataHandle<Location>[/+] on Aug 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402520 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.