Java generics compiles in eclipse, not command line

I know that similar problems have been discussed in several threads below, but I still cannot find a solution to my problem.

Other Topics: Compilers Behave Differently with a Generic Method Zero Parameter

Compiling Java generation code in eclipse but not on the command line

So, I wrote an event mechanism using events handler common to events and interfaces. I had code for logging events that generate an error on the javac command line, but not with the eclipse indigo. In the code below, EventRegistry simply captures the name of the event class and event handler in a string format.

I created the following interfaces

 public interface Event{} public interface EventHandler<T extends Event> {} 

Methods in the EventManager class

 public <T extends Event, P extends EventHandler<T>> void registerManagedHandler( EventRegistry er, ClassLoader cl ) throws ClassNotFoundException { ... Class<T> eventClass = (Class<T>) cl.loadClass(er.getEventClass()); Class<P> eventHandlerClass = (Class<P>) cl.loadClass(er.getEventHandlerClass()); ... register(eventHandlerClass, eventClass); } private <T extends Event, P extends EventHandler<T>> void register( Class<P> handler, Class<T> eventClass ) { ... } 

... in some other class. I have an expression.

 EventManager.getInstance().registerManagedHandler(er,al); 

Eclipse compiles code correctly, but an error occurs when compiling from javac on the command line

 incompatible types; inferred type argument(s) com.mycompany.events.Event,java.lang.Object do not conform to bounds of type variable(s) T,P [javac] found : <T,P>void [javac] required: void [javac] EventManager.getInstance().registerManagedHandler(er,al); 

There are similar methods for unregistering/enabling/disabling events that generate the same error. From the above code, I tried to remove type constraints ( <T extends Event, P extends EventHandler<T>> ) from registerManagedHandler, but then register (...) the method caused by the generated error

my modified registeredManagedHandler () ..

 public void registerManagedHandler( EventRegistry er, ClassLoader cl ) throws ClassNotFoundException { ... Class<? extends Event> eventClass = (Class<? extends Event>) cl.loadClass(er.getEventClass()); Class<? extends EventHandler<? extends Event>> eventHandlerClass = (Class<? extends EventHandler<? extends Event>>) cl.loadClass(er.getEventHandlerClass()); ... register(eventHandlerClass, eventClass); } 

New generated compilation time Error in eclipse too.

 Bound mismatch: The generic method register(Class<P>, Class<T>) of type EventManager is not applicable for the arguments (Class<capture#20-of ? extends EventHandler<? extends Event>>, Class<capture#22-of ? extends Event>). The inferred type capture#20-of ? extends EventHandler<? extends Event> is not a valid substitute for the bounded parameter <P extends EventHandler<T>> 

I do not intend to remove type checks from the register (...) method.

Please let me know if more details about the code are required for understanding.

Please tell me the correct way to solve such problems or workarounds. I am new to generics, but before implementing this, I read the basic guides.

Also, I could not find a way to force eclipse to use sun-javac6 installed on my Ubuntu system instead of my own compiler. Although I know how to change the JRE in eclipse (Project -> Properties -> Java Build Path -> Libraries)

Thanks in advance.

Update: Thank you guys for your answers. Tell me if I can provide more information. My version of Eclipse is Indigo (3.7)

Here sscce. If you run the program in eclipse, it works fine (compilation and execution). But when you start it using the command line: i.e. Javac GenericTester.java, the following error appears. I confirmed this with the sscce.org compilation tool.

 interface Event { } interface EventHandler<T extends Event> { } class EventRegistry { public String eventClass; public String eventHandlerClass; } class EventManager { public <T extends Event, P extends EventHandler<T>> void registerEvent( Class<T> eventClass, Class<P> eventHandlerClass) { } public <T extends Event, P extends EventHandler<T>> void registerEvent( EventRegistry er) throws ClassNotFoundException { Class<T> eventClass = (Class<T>) this.getClass() .getClassLoader().loadClass(er.eventClass); Class<P> eventHandlerClass = (Class<P>) this .getClass().getClassLoader() .loadClass(er.eventHandlerClass); registerEvent(eventClass, eventHandlerClass); } } class MyEvent implements Event { } class MyEventHandler implements EventHandler<MyEvent> { } public class GenericTester { public static void main(String[] args) { EventRegistry er = new EventRegistry(); er.eventClass = MyEvent.class.getName(); er.eventHandlerClass = MyEventHandler.class.getName(); try { new EventManager().registerEvent(er); System.out.println("It worked."); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 

An error from the command line, including the command I run:

 nitiraj@pandora :~/mywork/GenericTest/src$ javac GenericTester.java GenericTester.java:40: incompatible types; inferred type argument(s) Event,java.lang.Object do not conform to bounds of type variable(s) T,P found : <T,P>void required: void new EventManager().registerEvent(er); ^ Note: GenericTester.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 1 error 

Additional information about java that I installed.

 nitiraj@pandora :~/mywork/GenericTest/src$ java -version java version "1.6.0_30" Java(TM) SE Runtime Environment (build 1.6.0_30-b12) Java HotSpot(TM) 64-Bit Server VM (build 20.5-b03, mixed mode) nitiraj@pandora :~/mywork/GenericTest/src$ javac -version javac 1.6.0_30 
+4
source share
3 answers

This is a bug in java 5 and java 6, fixed in java 7

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6369605

+2
source

I don’t think we have enough information to answer your first question. However, for your second question, you can configure the Java Runtime runtime using Preferences → Java → Installed JREs , and you can configure the Java Compiler compliance level using Preferences → Java → Compiler

enter image description here

0
source

Why JDK 1.6 refused to compile what SSCCE explained at: Compilers behave differently with a null parameter of the generic method

In Java 7, the output algorithm for variable types that do not appear in parameter types or return values ​​is extended to accept type parameters. Indeed, your SSCCE successfully compiles with javac from JDK 1.7.0_02.

However, I think your registerEvent uses generalizations: method type parameters are set by the caller (usually by the type inference algorithm, but they can only be specified explicitly), but your code is only correct if the arguments of the actual type to the callers match the arguments of EventRegistry. which are not checked by the compiler. Consider:

  er.eventHandlerClass = "java.lang.String"; new EventManager().<MyEvent, MyEventHandler>registerEvent(er); 

That compiles and works fine, but is likely to throw a ClassCastException when the event is actually fired. Therefore, I would not recommend passing classes as strings.

If you really need them to be Strings in order to get an idea of ​​ClassLoader, you should at least check that the classes implement the correct types:

 public void registerEvent(EventRegistry er) throws ClassNotFoundException { Class<? extends Event> eventClass = this.getClass() .getClassLoader().loadClass(er.eventClass) .asSubclass(Event.class); Class<? extends EventHandler> eventHandlerClass = this .getClass().getClassLoader() .loadClass(er.eventHandlerClass) .asSubclass(EventHandler.class); registerEvent(eventClass, eventHandlerClass); } 

With this implementation, trying to subscribe String as an EventHandler will result in a ClassCastException .

This code is still not perfect, since a compiler warning warns us that I am not checking that the EventHandler has the correct type parameter, so the caller can still do:

  er.eventClass = Event.class.getName(); er.eventHandlerClass = MyEventHandler.class.getName(); new EventManager().registerEvent(er); 

although MyEventHandler cannot handle all Event s. However, checking the type of the EventHandler event is generally not possible due to type erasure.

0
source

Source: https://habr.com/ru/post/1403309/


All Articles