Java compilation error: switch on enum - java

I came across a very weird error that I just can't figure out how to solve.
A project, that compiles just fine on Windows, doesn't compile on Linux with the following error:
Cannot switch on a value of type AClass.Bbb. Only convertible int values, strings or enum variables are permitted, even though the stated type is an enum.
The code of the class is something along these lines:
public class AClass {
private enum Bbb {
ONE,
TWO;
}
public void aMethod(List<Bbb> arg) {
for (Bbb en : arg) {
switch (en) {
....
}
}
}
}
The en in switch(en) is underlined, with the error notification stated above.
Has anyone else had it? Is there a way to solve this?
UPD Java version:
java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)

The problem should go away if u r using JDK1.7 .Try following the below steps and see
Open the project properties
Click on "Java Compiler"
Checkmark "Enable project specific settings"
Set all of the drop down menus to 1.7
Hit ok
Clean the project to trigger a rebuild
If u do below , then the problem reappears.
Open the project properties
Click on "Java Compiler"
Clear "Enable project specific settings"
Hit ok
Clean the project to trigger a rebuild (it will rebuild automatically)
Here's what I see if I do the following...
Open the project properties
Click on "Java Compiler"
Click on "Configure Workspace Settings"
I see that the "Compiler compliance level" = 1.7
I see that "Use default compliance settings" is checked.
Hope this helps!!

I have tried your code
public class AClass {
enum Bbb {
ONE,
TWO;
}
public void aMethod(List<Bbb> arg) {
for (Bbb en : arg) {
switch (en) {
case ONE: System.out.println("ONE");break;
case TWO: System.out.println("TWO");break;
}
}
}
public static void main(String[] args) {
List<Bbb> list = new ArrayList<Bbb>();
list.add(Bbb.ONE);
list.add(Bbb.TWO);
new AClass().aMethod(list);
}
}
It is working fine.I dont know the pros and cons of passing argument like this List<Bbb> arg but atleast it is not error as much as i know in java 7

I don't know whether it is windows/linux related issue. But
From jdk5 onwards you can use enum in switch case and from jdk7 you can use String in switch case. While using enum in switch make sure that:
you are using jdk5 and later
All the labels used in your switch must be a valid enum object inside
your enum being used in switch.
In java enum is implemented through class concept(Each n every enum in java extends to Enum class that is an abstract class and direct sub class of Object class). So while creating enum like
public enum Bbb {
ONE,
TWO;
}
It will internally meant
public static final Bbb ONE=new Bbb();
public static final Bbb TWO=new Bbb();
Means all your defined enum objects are public, final and static objects of defined enum class. If you are using something else as switch label, it will give a compile time error.
For each enum in java, super class Enum is final and all enum classes are internally implemented as final. So inheritance can not be used for enum in java. Means we are not allowed to use anything else in switch labels except our own class enum objects(Not even subclass objects, because enum class can't be inherited further)

Related

Eclipse autocompletion for jdk.* packages does not work

I write here because I noticed a strange behaviour of Eclipse IDE (2022-12).
Basically, the autocompletition does not work properly when I use a class from a jdk.* package.
For example:
import jdk.jshell.*;
public class Test {
private static final JShell JSHELL = JShell.create();
...
...
public static void main(String[] args) {}
}
Now when I write JSHELL. (e.g., inside the main method), I get only proposal for the methods of the Object class. No specific proposal is available.
What am I doing wrong?
Thanks.
Tried updating & reinstalling Eclipse.
jdk.* is filtered by default.
When you want to use something of jdk.* in a project, go to the preferences Java > Appearance > Type Filters and uncheck the item jdk.*.

Switch Enum in Java in Zookeper [duplicate]

I came across a very weird error that I just can't figure out how to solve.
A project, that compiles just fine on Windows, doesn't compile on Linux with the following error:
Cannot switch on a value of type AClass.Bbb. Only convertible int values, strings or enum variables are permitted, even though the stated type is an enum.
The code of the class is something along these lines:
public class AClass {
private enum Bbb {
ONE,
TWO;
}
public void aMethod(List<Bbb> arg) {
for (Bbb en : arg) {
switch (en) {
....
}
}
}
}
The en in switch(en) is underlined, with the error notification stated above.
Has anyone else had it? Is there a way to solve this?
UPD Java version:
java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
The problem should go away if u r using JDK1.7 .Try following the below steps and see
Open the project properties
Click on "Java Compiler"
Checkmark "Enable project specific settings"
Set all of the drop down menus to 1.7
Hit ok
Clean the project to trigger a rebuild
If u do below , then the problem reappears.
Open the project properties
Click on "Java Compiler"
Clear "Enable project specific settings"
Hit ok
Clean the project to trigger a rebuild (it will rebuild automatically)
Here's what I see if I do the following...
Open the project properties
Click on "Java Compiler"
Click on "Configure Workspace Settings"
I see that the "Compiler compliance level" = 1.7
I see that "Use default compliance settings" is checked.
Hope this helps!!
I have tried your code
public class AClass {
enum Bbb {
ONE,
TWO;
}
public void aMethod(List<Bbb> arg) {
for (Bbb en : arg) {
switch (en) {
case ONE: System.out.println("ONE");break;
case TWO: System.out.println("TWO");break;
}
}
}
public static void main(String[] args) {
List<Bbb> list = new ArrayList<Bbb>();
list.add(Bbb.ONE);
list.add(Bbb.TWO);
new AClass().aMethod(list);
}
}
It is working fine.I dont know the pros and cons of passing argument like this List<Bbb> arg but atleast it is not error as much as i know in java 7
I don't know whether it is windows/linux related issue. But
From jdk5 onwards you can use enum in switch case and from jdk7 you can use String in switch case. While using enum in switch make sure that:
you are using jdk5 and later
All the labels used in your switch must be a valid enum object inside
your enum being used in switch.
In java enum is implemented through class concept(Each n every enum in java extends to Enum class that is an abstract class and direct sub class of Object class). So while creating enum like
public enum Bbb {
ONE,
TWO;
}
It will internally meant
public static final Bbb ONE=new Bbb();
public static final Bbb TWO=new Bbb();
Means all your defined enum objects are public, final and static objects of defined enum class. If you are using something else as switch label, it will give a compile time error.
For each enum in java, super class Enum is final and all enum classes are internally implemented as final. So inheritance can not be used for enum in java. Means we are not allowed to use anything else in switch labels except our own class enum objects(Not even subclass objects, because enum class can't be inherited further)

Why can't Maven compile a Java enum with overloaded methods while Eclipse can?

If I declare a method in a Java† enum instance (e.g. SwallowSpecies.AFRICAN.calculateMaxAirspeedVelocity()) which overloads a static method of the enum class (e.g. SwallowSpecies.calculateMaxAirspeedVelocity(double, double)), compiling with Maven‡ results in the following compilation error:
method calculateMaxAirspeedVelocity in enum cannot be applied to given types;
required: no arguments
found: double,double
reason: actual and formal argument lists differ in length
For some reason, the compiler can't find the method without it being qualified with its class SwallowSpecies. However, why is the exact same code valid according to the compiler used internally by Eclipse§ for building?— here is the relevant code:
public enum SwallowSpecies {
AFRICAN {
double calculateMaxAirspeedVelocity() {
// This line compiles within Eclipse but not when compiling with Maven
return calculateMaxAirspeedVelocity(3.0, 0.5);
// This line compiles both with Maven's and with Eclipse's compiler
// return SwallowSpecies.calculateMaxAirspeedVelocity(3.0, 0.5);
}
};
private static double calculateMaxAirspeedVelocity(final double maxWeight, final double weightRatio) {
// Dummy logic
return 1.0;
}
}
Interestingly, an analogous case using an inner class instead of an enum is invalid both for Eclipse's compiler and for Maven's— What's the difference here?
public class SwallowSpecies {
private static class African {
double calculateMaxAirspeedVelocity() {
// This line doesn't compile
return calculateMaxAirspeedVelocity(3.0, 0.5);
// This line does
// return SwallowSpecies.calculateMaxAirspeedVelocity(3.0, 0.5);
}
}
private static double calculateMaxAirspeedVelocity(final double maxWeight, final double weightRatio) {
// Dummy logic
return 1.0;
}
}
†I tested this phenomenon using Maven's compiler source and target settings set to 1.6, 1.7 and 1.8 and it occurs with all of these different settings.
‡Tested using Maven version 3.16.0-38-generic and using
Oracle's JDK version 1.8.0_91 from Ubuntu's DEB oracle-java8-installer version 8u92+8u91arm-2~really8u91~webupd8~0 as well as with
OpenJDK version 1.7.0_101 from Ubuntu's DEB openjdk-7-jdk version 7u101-2.6.6-0ubuntu0.14.04.1
§Version 4.5.2; build ID 20160218-0600
There are indeed some differences between the oracle and the eclipse compiler.
Eclipse uses its own compiler because
it allows to run and debug code which still contains unresolved errors.
see enter link description here
Different implementations bring the risk of different behavior, as you found here.
So far I always found the Oracle or OpenJdk compiler (that I use in maven) to be more strict than eclipse.
In very rare cases (not more than once a year I would say) I had to make small adjustments so code compiles in maven as well as in eclipse.

default method in interface runs with command prompt but not in eclipse

interface G {
default void print() {
System.out.println("G");
}
}
class M {
public void print() {
System.out.println("M");
}
}
class GImpl extends M implements G {}
public class Wierd {
public static void main(String[] args) {
G g=new GImpl();
g.print();
}
}
i was trying to use default method in interface ,but when compile with eclipse i get error on line 2 -says delete default, but i compile and run with command prompt it runs fine,what could be the reason for this?
Your eclipse still not using Java8 version please check it might be less than 8.
Use System.out.println(System.getProperty("java.runtime.version")); to check.
You may also need to change build path of your project and compiler level in eclipse.
AND More Important:
Installing Java™ 8 support .
It seems that you have installed Java 8 JDK but your eclipse still does not support Java 8. Eclipse Luna has support for Java 8. To change the compiler options Right Click your project>Properties>Java Compiler>Check on "Enable project specific settings">Then select Compiler Compliance level.

Java compilation issue on Linux, using Windows specific

I encountered a compilation issue under Linux.
I'm compiling java programs on Linux; the target use is both Linux and Windows.
The code check if in there are platform specific classes (as shown in the code below).
So if the code is running under Linux, the specific Windows code will not be executed.
The issue arise on the use of a platform specific class Win32MediaTray
The compile error reported is
PrinterScanner.java:9: error: cannot find symbol
import sun.print.Win32MediaTray;
^
Is it possible to compile it under Linux? Or is it just impossible?
I can use some workaround (reflection?)
Needless to say that the compilation under Windows gives no errors.
Thankyou for your help.
For reference, the code behind this issue is the following:
private String getTrayName(Media media) {
String result = "id:" + media.getValue();
boolean isWin32 = media.getClass().getName().equals("sun.print.Win32MediaTray");
if (isWin32) {
Win32MediaTray w32 = (Win32MediaTray) media;
result = result + ",winId:" + w32.winID;
}
return result;
}
I believe that the class you are trying to use is sun.print.Win32MediaTray.
And the answer is that you cannot use it ... or compile a class that uses it ... on a Linux release of Java. That class is not included in the rt.jar file on a Linux release of Java.
Furthermore, you shouldn't be using it. The Java documentation makes it very clear that application code should not make use of classes in the sun.* package hierarchy.
If you have no choice but to do this, then your best bet is to use reflection to fetch the value of that w32Id field. You'll also need to deal with the case where the media object is not an instance of the Win32MediaTray class. Beware that you are relying on implementation details that Oracle says specifically that you shouldn't. There is a risk that they will change (without notice!) in some future Windows release.
The other alternatives are:
Implement your own platform adapter classes with a different one for each platform. These have to be compiled separately on each platform, and then dynamically loaded.
Implement separate codebases for each platform.
To make the compiler happy you could implement a dummy class named sun.print.Win32MediaTray and make it available both on the compile and runtime classpath. The class doesn't need to work, it only has to be API compatible (same signatures and return types, but in this case you only really need to extend Media and have a public int winID), so that you can satisfy both the compiler and the verifier.
At runtime, the version included in rt.jar should be loaded on Windows thanks to loading delegation. On Linux, the dummy version is the only one available, but you stated that the program checks for the platform and executes another branch of code, so it shouldn't cause your program to fail.
For example, with the following class on the classpath:
package sun.print;
import javax.print.attribute.standard.Media;
public class Win32MediaTray extends Media {
public int winID = 0xBADC0DE;
protected Win32MediaTray(int value) {
super(value);
}
static {
System.out.println("Won't see me on Windows");
}
}
I managed to run this program on Windows:
public class Main {
public static void main(String[] args) {
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
for (PrintService svc : services ) {
DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PAGEABLE;
Object o = svc.getSupportedAttributeValues(Media.class, flavor, null);
if (o != null && o.getClass().isArray()) {
for (Media media : (Media[]) o) {
if ( media instanceof Win32MediaTray )
System.out.println( ((Win32MediaTray) media).winID );
}
}
}
}
}
The message in the static initializer is not printed on Windows, because the definition that is actually loaded is the one from rt.jar. Obviously, the code can be compiled on any platform.
How about putting the code that uses windows-specific stuff into a separate jar; then you can compile and include that jar on windows, and leave it off systems otherwise.
One standard way to do this is to have one or more interfaces used by your application code; you can have a factory provide the implementing classes or inject them with Spring or whatever. But I think rather than "how can I compile this on Linux" your question should be "I have this Windows dependency in an app targeted at multiple operating systems, how do I handle it?"

Categories

Resources