Reference to Public Enum results in Anonymous Class - java

I'm getting an anonymous class at compile-time that I'm not expecting. Relevant code follows, then a more detailed explanation:
Entirety of CircuitType.java:
public enum CircuitType { V110A20, V110A30, V208A20, V208A30 }
From Auditor.java, lines 3-9:
public class Auditor {
private String[] fileNames;
private int numV110A20;
private int numV110A30;
private int numV208A20;
private int numV208A30;
From Auditor.java, lines 104-121:
[...]
switch (newCircuit.getType()) {
case V110A20:
this.numV110A20++;
break;
case V110A30:
this.numV110A30++;
break;
case V208A20:
this.numV208A20++;
break;
case V208A30:
this.numV208A30++;
break;
default:
System.err.println("An Error Has Occured.");
System.exit(-1);
break;
}
[...]
From Circuit.java, lines 1-5:
public class Circuit {
private CircuitType myType;
public CircuitType getType() {
return this.myType;
}
[...]
When the command
javac *.java
is executed, an anonymous class Auditor$1.java is generated. The files, obviously, all sit next to each other in a file system directory that contains nothing else.
When lines 104-121 are commented out, no anonymous class is generated.
I at first thought it was a package issue, so put the three classes in a package, but I didn't know enough about packages to get it working. If it's truely a package issue, can someone step me through exactly how to label them? I'd rather not have to package them if I don't have to, though.
The reason the anonymous class is a problem, besides the fact that such classes usually signify a namespace issue, is that it breaks my Makefile I use for automatic compilation.
Update
Attached is a console session which I hope may shed light on this mystery:
% javap 'Auditor$1'
Compiled from "Auditor.java"
class Auditor$1 extends java.lang.Object{
static final int[] $SwitchMap$CircuitType;
static {};
}

I've gone ahead and built a little project containing the source you posted and just enough framework around it to make it compile. I got 3 class files: Circuit.class, CircuitType.class and Auditor.class - as expected.
All this under Java 1.6. But as others have indicated, I think your diagnosis of the problem is off.
Anonymous classes are easy to generate accidentally: Typically a construct like
Circuit myCircuit = new Circuit() {
public CircuitType getCircuitType() {
return XXX;
}
}
will create one, for example. Given more of your code, the good SO folks might be able to pinpoint your error.
It might be interesting and instructive to disassemble your class files with javap or better yet a "real" Java disassembler like JD.
Update
Added your new Auditor code to mine... no change. No anonymous classes.
Your code is of course correct (to the extent we can see it) but the design is not very OO. Some people would point out that you'll have to extend your counter declarations and your switch statement every time a new circuit type appears.
You're also not making much use of the "special features" of enums. I have a much simplified version of your Auditor method:
private int[] counters = new int[CircuitType.values().length];
public void tallySomething() {
Circuit newCircuit = new Circuit();
counters[newCircuit.getType().ordinal()]++;
}
Update 2
I found your javap output quite illuminating. See my comment below.
My conclusions:
Yes, apparently your Java impl is using an anon class for the switch. Lame, but legitimate.
You have the following options:
eliminate the switch
use a different Java implementation
live with the anonymous class; ditch make and use ant to embrace the anon classes and other strangenesses of Java.
Since you're only having problems because of your non-standard compilation setup, I'd go with the last solution and attack the problem there.

It indeed appears that (in certain cases at least) an inner class will be generated for the switch statement:
Java enum and additional class files

Related

Issue with ASM getMergedType and getCommonSuperClass

I use ASM to update the class stack map, but when asm getMergedType, the following exception occurs:
java.lang.RuntimeException:
java.io.IOException: Resource not found for IntefaceImplA.
If without asm modify the class method, it does work fine.
I have defined two interfaces A and B: IntefaceImplA and
IntefaceImplB.
My environment source code:
IntefaceA.java
public interface IntefaceA {
void inteface();
}
IntefaceImplA.java
public class IntefaceImplA implements IntefaceA {
#Override
public void inteface() {
}
}
IntefaceImplB.java
public class IntefaceImplB implements IntefaceA {
#Override
public void inteface() {
}
}
Test.java
public class Test {
public IntefaceA getImpl(boolean b) {
IntefaceA a = b ? new IntefaceImplA() : new IntefaceImplB();
return a;
}
}
Main.java
public class Main {
public static void main(String args[]) {
....
if (a instance of Test) {
..
...
}
}
}
After I compiled a runner jar, and delete the IntefaceImplA.class and IntefaceA.class manually from the jar. why i wanna to delete those classes files, since the spring always like to do this stuff.
the runner jar can be run normal without ASM, but use Asm will occur exception. since the asm wanna to getMergedType for IntefaceImplA and IntefaceImplB, but IntefaceImplA was deleted by me.
After investigate the ASM ClassWriter source code i found below code:
protected String getCommonSuperClass(String type1, String type2)
{
ClassLoader classLoader = this.getClass().getClassLoader();
Class c;
Class d;
try {
c = Class.forName(type1.replace('/', '.'), false, classLoader);
d = Class.forName(type2.replace('/', '.'), false, classLoader);
} catch (Exception var7) {
throw new RuntimeException(var7.toString());
}
if(c.isAssignableFrom(d)) {
return type1;
} else if(d.isAssignableFrom(c)) {
return type2;
} else if(!c.isInterface() && !d.isInterface()) {
do {
c = c.getSuperclass();
} while(!c.isAssignableFrom(d));
return c.getName().replace('.', '/');
} else {
return "java/lang/Object";
}
}
Actually, I deleted the related class file, the classloader cannot find the class. but without asm the Program does work normal.
Should I enhance the override to the getCommonSuperClass method, if occur exception then return java/lang/Object for it? that's funny
Generally, overriding getCommonSuperClass to use a different strategy, e.g. without loading the class, is a valid use case. As it’s documentation states:
The default implementation of this method loads the two given classes and uses the java.lang.Class methods to find the common super class. It can be overridden to compute this common super type in other ways, in particular without actually loading any class, or to take into account the class that is currently being generated by this ClassWriter, which can of course not be loaded since it is under construction.
Besides the possibility that either or both arguments are classes you are currently constructing (or changing substantially), it might be the case that the context of the code transforming tool is not the context in which the classes will eventually run, so they don’t have to be accessible via Class.forName in that context. Since Class.forName uses the caller’s context, which is ASM’s ClassWriter, it is even possible that ASM can’t access the class despite it is available in the context of the code using ASM (if different class loaders are involved).
Another valid scenario is to have a more efficient way to resolve the request by using already available meta information without actually loading the class.
But, of course, it is not a valid resolution to just return "java/lang/Object". While this is indeed a common super type of every argument, it isn’t necessarily the right type for the code. To stay with your example,
public IntefaceA getImpl(boolean b) {
IntefaceA a = b ? new IntefaceImplA() : new IntefaceImplB();
return a;
}
the common super type of IntefaceImplA and IntefaceImplB is not only required to verify the validity of assigning either type to it, it is also the result type of the conditional expression, which must be assignable to the return type of the method. If you use java/lang/Object as common super type, a verifier will reject the code as it can’t be assignable to IntefaceA.
The original stackmap, very likely reporting IntefaceA as common super, will be accepted by the verifier as that type is identical to the method’s return type, so it can be considered assignable, even without loading the type. The test, whether either, IntefaceImplA and IntefaceImplB, is assignable to that specified common type, might be postponed to the point where these types are actually loaded and since you said, you deleted IntefaceA, this can never happen.
A method whose declared return type is absent, can’t work at all. The only explanation of your observation that “without asm the program does work normal”, is, that this method was never invoked at all during your test. You most probably created a time bomb in your software by deleting classes in use.
It’s not clear why you did this. Your explanation “since the spring always like to do this stuff” is far away from being comprehensible.
But you can use the overriding approach to get the same behavior as with the unmodified code. It just doesn’t work by return java/lang/Object. You could use
#Override
protected String getCommonSuperClass(String type1, String type2) {
if(type1.matches("IntefaceImpl[AB]") && type2.matches("IntefaceImpl[AB]"))
return "IntefaceA";
return super.getCommonSuperClass(type1, type2);
}
Of course, if you deleted more class files, you have to add more special cases.
An entirely different approach is not to use the COMPUTE_FRAMES option. This option implies that ASM will recompute all stack map frames from scratch, which is great for the lazy programmer, but implies a lot of unnecessary work if you are just doing little code transformations on an existing class and, of course, creates the requirement to have a working getCommonSuperClass method.
Without that option, the ClassWriter will just reproduce the frames the ClassReader reports, so all unchanged methods will also have unchanged stack maps. You will have to care about the methods whose code you change, but for a lot of typical code transformation tasks, you can still keep the original frames. E.g. if you just redirect method calls to signature-compatible targets or inject logging statements which leave the stack in the same state it was before them, you can still keep the original frames, which happens automatically. Note the existence of the ClassWriter(ClassReader,int) constructor, which allows an even more efficient transfer of the methods you don’t change.
Only if you change the branch structure or insert code with branches, you have to care for frames. But even then, it’s often worth learning how to do this, as the automatic calculation is quiet expensive while you usually have the necessary information already when doing a code transformation.

Errors in evaluation of ClassName.EnumName

I have a class say ClassX with enum defined. like so
public class ClassX{
public enum XType {
E_1, E_2, E_3, E_TC, UN_KNOWN, N_ONE;
}
}
In method (methodx) in another class I am referring to the enum and assigning it to another variable like so:
public class AnotherClass{
public class NestedClass {
// some member variables
public NestedClass(String x, CustomClass y) {
this.m1 = x;
this.m2 = y;
this.b1 = false;
this.b2 = false;
}
}
public SomeType methodx() {
XType xt = null;
try {
// print log stmt1
xt = XType.E_TC;
// print log stmt2
}
catch(Exception e) {
// print log stmt3
}
}
}
The problem is that i get log stmt1 in log. But don't get anything after that from the methodx().
I spent hours trying to figure out what was wrong. The logs were not getting printed and nor was there any exception thrown/caught. Then, I attached debugger. Put breakpoints just before the assignment. When the breakpoint was hit, I added the XType.E_TC to the watch list.
To my surprise it said <Errors Evaluating>. I still went ahead with my stepping and the code jumped to constructor block of subclass block above the methodx()!
This doesn't make sense to me as the classes are correctly compiled and classes load correctly. I checked for XType by executing "javap" separately and there is no error.
Have you seen something like this before?
How to fix this?
Why does such a thing happen in the first place? I mean I can understand if the .class file of ClassX is partially built and doesn't have definition for XType, this is plausible. But the class definition and enum are correctly compiled into the .class. as mentioned above, I verified it using the javap command.
Any help and pointers are very much appreciated!
"It may be that you have one or more stale class files somewhere" does look like the most likely reason: your code was compiled but linked wrongly (probably, with some leftover object files) at runtime.
Explore the app's state at breakpoint hit in more details: if XType is loaded, from which location, how it looks, if the other entities from that compilation unit are present (add one for a test and see if it appears at runtime). Alternatively, you may do a clean build in another directory and look for differences in the runtime state.
The issue was that the dependent class was not available on classpath.
I would expect ClassNotFoundException in such a case. But for reasons known to JBoss EAP6 server, it was printing this in "TRACE" level.
When I provided the correct jar file on classpath, it did not give me any error.
Am still not able to reconcile the fact that when class is not found, JBoss EAP server chose to report it in TRACE!

Class '...' must be declared as 'abstract'. Checkstyle

I have this warning on most of my classes and not sure why is that. This happens on both public normal classes and final classes which have private constructors, some no constructor at all. I tried changing my private class methods to protected, doesn't help. Any suggestions on how to turn this off?
Here's a class example
public final class PlanBenefitManagerAssembler {
private static final Logger LOGGER = Logger.getLogger(PlanBenefitManagerAssembler.class);
/**
* No Instance of the this class is allowed.
*/
private PlanBenefitManagerAssembler() {
}
public static List<BenefitDecisionDetailsBean> assembleBenefitDecisionDetailsBean(
List<BenefitDetails> benefitDecisionDetailsList, int relationalSequenceNumber) {
LOGGER.debug("Enter assembleBenefitDecisionDetailsBean");
List<BenefitDecisionDetailsBean> benefitDecisionDetailsBeanList = new ArrayList<BenefitDecisionDetailsBean>();
for (BenefitDetails benefitDecisionDetails : benefitDecisionDetailsList) {
BenefitDecisionDetailsBean benefitDecisionDetailsBean = new BenefitDecisionDetailsBean();
benefitDecisionDetailsBean.setBenefitTypeCode(benefitDecisionDetails.getBenefitTypeCode());
benefitDecisionDetailsBean.setRelationSequenceNumber(relationalSequenceNumber);
benefitDecisionDetailsBean.setBenefitStatusDescription(
benefitDecisionDetails.getBenefitStatusDescription());
benefitDecisionDetailsBean.setBenefitStatusCode(benefitDecisionDetails.getBenefitStatusCode());
benefitDecisionDetailsBean.setBenefitUnderwritingStatusCode(
benefitDecisionDetails.getBenefitUnderwritingStatusCode());
benefitDecisionDetailsBean.setBenefitUnderwritingStatusDescription(
benefitDecisionDetails.getBenefitUnderwritingStatusDescription());
benefitDecisionDetailsBean.setBenefitChangeReasonCode(
String.valueOf(benefitDecisionDetails.getBenefitChangeReasonCode()));
benefitDecisionDetailsBean.setBenefitChangeReasonDescription(
benefitDecisionDetails.getBenefitChangeReasonDescription());
benefitDecisionDetailsBean.setComponentNumber(benefitDecisionDetails.getBenefitNumber());
benefitDecisionDetailsBean.setBenefitVisible(benefitDecisionDetails.isExplicitBenefitDecisionRequired());
benefitDecisionDetailsBean.setModelChanged(false);
// * Set BenefitLoading and BenefitExclusion
List<ExclusionDetailsBean> exclusionDetailsBeanList =
PlanBenefitManagerAssembler.assembleExclusionDetailsList(benefitDecisionDetails
.getBenefitExclusionsDetailsList().getBenefitExclusionsDetailsList());
List<LoadingDetailsBean> loadingDetailsBeanList =
PlanBenefitManagerAssembler.assembleLoadingDetailsList(benefitDecisionDetails
.getBenefitLoadingsDetailsList().getBenefitLoadingsDetailsList());
benefitDecisionDetailsBean.setExclusionDetailsBeanList(exclusionDetailsBeanList);
benefitDecisionDetailsBean.setLoadingDetailsBeanList(loadingDetailsBeanList);
benefitDecisionDetailsBeanList.add(benefitDecisionDetailsBean);
}
LOGGER.debug("Exit assembleBenefitDecisionDetailsBean");
return benefitDecisionDetailsBeanList;
}
}
When Checkstyle produces a warning the warning text should include a short rule name which will allow you to look up the exact rule that is being triggered. "DesignForExtension", for example.
Given the rule name, you can look up more detail on what it means in the Checkstyle documentation: http://checkstyle.sourceforge.net/availablechecks.html
Post the full details of the rule being triggered and someone might be able to help.
You can always turn the warnings off, but they generally are here for a reason :)
Do you intend to make them abstract classes ? If so, declare them that way.
Will you need to instantiate them at some point ? If so, add a public constructor.
I'm pretty sure this will solve your problem.
On sourceforge it says that the AbstractClassName rule uses the following regex:
^Abstract.*$|^.*Factory$
This causes classes with a name starting with 'Abstract' or ending with 'Factory' to be flagged. I get the 'Abstract..' part of that, but why should all '..Factory' classes be abstract? Sometimes I create factories which use dependencies to do their work so I need an instance to inject into.
This however does not explain your case. I tried your example class and did not get any Checkstyle warning (I am using the Eclipse Checkstyle Plug-in version 5.3.0.201012121300).
Are you sure you are getting the AbstractClassName warning for this class? Which version of Checkstyle are you using?

Object instantiation when dependency is missing (Java)

Guys, can anyone explain the following scenario:
1) Web application has module1.jar in its lib directory. There is a class A in that module:
package module1;
import module2.B;
public interface IA {
void methodOk() {}
void methodWithB(B param) {}
}
package module1;
import module2.B;
public class A implements IA {
public A() {}
//...
void methodWithB(B param) {
//do job on B
}
}
2) module2.jar is absent - it is not in the classpath.
3) Application is able to create objects of class A though it's missing the dependency. In application a method A.methodOk() is called.
Would be cool if you could give a reference to any spec on this.
Thanks a lot.
Since the code is already compiled, it will not throw an error until you directly use class B. From the looks of your code, you don't actually use an instance of B for anything.
If B is not used by A anywhere, then the resulting bytecode will have no reference to module2.B, therefore it gets compiled away. No dependency exists, except at compilation in this case.
If the question is unclear and B is used in A somewhere, then I'd be interested in seeing more code to try to determine what's going on.
Look at it from the perspective of the classloader. If you never have to load the class, you don't care if the bytecode for that class is missing.
Your question is really, "What triggers classloading?"
Two reasons I can think of off the top of my head are:
- Construction
- Static access

How do you add classes to a main method

I have three .java files and I need to get them to work together. I think that I need to add all the classes to a main method but I am not sure if this is correct and if I just add the name of the class and the format.
I figured it out, the three files had a package listed at the top of each. I created a new Java project in Eclipse and then a source folder and in the source folder I created a package with the name that they all referenced. Now it runs. Thanks for all of you help for the Eclipse/Java beginner.
You are right: what you think is not right :P
Java can find the classes that you need, you can just use them straight away. I get the feeling that you come from a C/C++ background (like me) and hence think that you will need to "include" the other classes.
java uses the concept of namespaces and classpaths to find classes. Google around for it.
A little example of how variety of classes can be used together:
// A.java
public class A {
public void sayIt() { sysout("Said it by A!"); }
}
// B.java
public class B {
public void doIt() { sysout("Done it by B!"); }
}
// MainClass.java
public class MainClass {
public static void main(String[] args) {
A aObj = new A();
B bObj = new B();
aObj.sayIt();
bObj.doIt();
}
}
Note that there are no includes/imports here because all of the classes are in the same namespace. If they were not, then you'd need to import them. I will not add a contrived example for that coz its too much to type, but should google for it. Info should be easy enough to find.
Cheers,
jrh
If they are in the same package you do not need to do anything, as they are automatically imported for you, but otherwise you'll need to add import statements before your class declaration.
Once this is done, you can reference static members directly ie ClassB.staticMethod(); or instantiate the class ie ClassB classb = new ClassB();
But honestly, if you are this confused, you need to spend some more time doing tuturials.
http://eclipsetutorial.sourceforge.net/totalbeginner.html
http://download.oracle.com/javase/tutorial/getStarted/cupojava/index.html
http://www.freejavaguide.com/corejava.htm
I am not sure what you mean by "adding classes to a main method". If you want to make use of several classes inside your Java program, just import the needed classes/packages at the beginning and create an instance of each class as you go along.
I learned this from a beginner program called Jeroo
Basically if I want to create a new "Jeroo", I would write the following on my Main method:
Jeroo Bob = new Jeroo();
{ methods... }
So basically:
[class] [customnameofclass] = new [class]

Categories