I'm trying to compile in-memory a class that implements an interface.
I have an interface named CacheRule (in com/vpfw/proxy/logicRules/CacheRule.class).
I have a class named CacheRuleBean that I compile in-memory.
If this class does not implement CacheRule, compilations works. But if this class implements CacheRule, then the error is:
java.lang.NoClassDefFoundError: com/vpfw/proxy/logicRules/CacheRule (wrong name: com/vpfw/proxy/logicRules/CacheRuleBean)
Curiously, if I perform this compilation inside Eclipse, works.
But when I execute it from Tomcat, I get the previous error.
This is the code for the CacheRule interface:
package com.vpfw.proxy.logicRules;
public interface CacheRule
{
void executeRule();
}
This is the code for CacheRuleBean:
package com.vpfw.proxy.logicRules;
import com.vpfw.proxy.logicRules.CacheRule;
public class CacheRuleBean implements CacheRule
{
public void executeRule() {}
}
And the call to compile is:
String[] compilationOptions = { "-cp", classDir };
return (new CompilerService().compile("com.vpfw.proxy.logicRules.CacheRuleBean",
source, compilationOptions));
Where
classDir is the directory /home/app/WEB-INF/classes that contains the com folder of this project (classPath is correct, If I add another classes of this project as imports in CacheRuleBean, compile ok).
The name of the class I use is com.vpfw.proxy.logicRules.CacheRuleBean.
source is the source code of CacheRuleBean.
CompilerService is my implementation of compiler API, which works perfectly with all classes except those that implement an interface.
What can I be doing wrong?
Related
Edit: A follow-up question based on this discussion was published in the following link.
Android: How to manage common codebase in multiple libraries used by the same application
I have two android aar library projects: LibA using ClassA, and LibB using ClassB. Both libs have the same base package. both libs use the same class named BaseClass, currently resides separately within each lib in package name 'common'. BaseClass contains one method named baseMethod.
This creates two libs using a class with the same name and a different implementation.
this is how the classes look like:
ClassA:
package mybasepackage.a;
import mybasepackage.common.BaseClass;
public class ClassA {
BaseClass baseClass;
public ClassA() {
this.baseClass= new BaseClass();
}
public String myPublicMethod(){
return this.baseClass.baseMethod();
}
}
ClassB:
package mybasepackage.b;
import mybasepackage.common.BaseClass;
public class ClassB {
BaseClass baseClass;
public ClassB() {
this.baseClass = new BaseClass();
}
public String myPublicMethod(){
return this.baseClass.baseMethod();
}
}
BaseClass In LibA:
package mybasepackage.common;
public class BaseClass{
public String baseMethod() {
return "Called from ClassA";
}
}
BaseClass in LibB:
package mybasepackage.common;
public class BaseClass{
public String baseMethod() {
return "Called from ClassB";
}
}
When I try to compile both libs in the same app, it throws a duplicated class error: "Program type already present: mybasepackage.common.BaseClass", this happens because the compiler cannot know which BaseClass to compile since it resides within both libs.
My goal is to allow both aar libs to compile successfully within the same app, while providing different implementations for the BaseClass. More formally, LibA and LibB should compile in the same application such as:
Calling new ClassA().baseMethod() will return "Called from ClassA".
Calling new ClassB().baseMethod() will return "Called from ClassB".
Pre condition: I cannot change the base package name in one of the libs because it essentially creates an unwanted duplication of BaseClass.
NOTE: I'm aware this may not be possible via the aar approach. If that is truly the case, I'm willing to consider other deployment architectures as long as I'll be able to compile these libs with the same common class using different implementations, as described in the question.
My goal is to allow both aar libs to compile successfully within the same app, while providing different implementations for the BaseClass
That is not possible, sorry.
I'm aware this may not be possible via the aar approach.
It has nothing to do with AARs. You cannot have two classes with the same fully-qualified class name in the same app, period. It does not matter where those duplicate classes come from.
I'm willing to consider other deployment architectures as long as I'll be able to compile these libs with the same common class using different implementations, as described in the question.
That is not possible, sorry. Again: it does not matter where the duplicate classes come from. You simply cannot have duplicate classes.
Given your precondition you just can't do that in this way. You cannot have 2 different libraries in java with the same package name, which is the main problem that throws your error (and not the name of the classes).
What you can do and maybe if possible is the best way to handle with that is to merge the two libraries into just one and add two subpackages inside and then just import them:
import mybasepackage.common.a_name.BaseClass; // class A
import mybasepackage.common.b_name.BaseClass; // class B
This will prevent the duplication error because they just have the same name but from different packages.
Another idea if this way doesn't fit your expectation is to change the architecture by implementing another abstraction layer in which you define your BaseClass as an abstract method:
package mybasepackage.common;
public class abstract BaseClass{
public String myPublicMethod();
}
and then you just implement the method inside ClassA and ClassB:
public class ClassA implements BaseClass{
public ClassA() {
super();
}
#Override
public String myPublicMethod(){
// logic for A
}
}
NB note that the above implementation of class A is just a stub and it is not supposed to work as it is. Adapt to your need.
In any case by the way you can't have two packages with same classes name.
Just build three artifacts, because two artifacts will always require an exclude on one of the dependencies set. When the two -liba and -libb libraries depend on a third -base, -core or -common library, there are no duplicate classes - and if you want to keep the package name, just make the package name depend on all of them, alike a meta-package:
mybasepackage
|
mybasepackage-liba -> mybasepackage-common
|
mybasepackage-libb -> mybasepackage-common
mybasepackage-common
I was trying to compile a few files in a package in java. The package name is library. Please have a look at the following details.
This is my Directory Structure:
javalearning
---library
------ParentClass.java
------ChildClass.java
I tried to compile in the following way:
current directory: javalearning
javac library/ParentClass.java //this compilation works fine
javac library/ChildClass.java //error over here
The following is the ParentClass.java:
package library;
class Parentclass{
...
}
The following is the ChildClass.java:
package library;
class ChildClass extends ParentClass{
...
}
The error is as follows:
cannot access ParentClass
bad class file: .\library\ParentClass.class
Please remove or make sure it appears in the correct sub directory of the classpath
You've got a casing issue:
class Parentclass
That's not the same as the filename ParentClass.class, nor is it the same as the class you're trying to use in ChildClass: class ChildClass extends ParentClass.
Java classnames are case-sensitive, but Windows filenames aren't. If the class had been public, the compiler would have validated that the names matched - but for non-public classes, there's no requirement for that.
The fact that you've ended up with ParentClass.class suggests that at some point it was declared as ParentClass, but then you changed the declared name and when recompiling, Windows just overwrote the content of the current file rather than effectively creating Parentclass.class.
Make sure your declared class name exactly matches the filename. You may well want to delete all your class files before recompiling, just to get out of a confusing state.
I'm learning java packages in school and I'm able to create and use my package on netbeans perfectly but cannot do it from the lubuntu command line. I get an error: could not find or load main class. Here is the code but I know this is not the problem since it works perfectly in netbeans
package animals;
public class MammalInt implements Animal
{
public void eat()
{
System.out.println("Mammal eats");
}
public void travel()
{
System.out.println("Mammal travels");
}
public static void main(String args[])
{
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
package animals;
interface Animal
{
public void eat();
public void travel();
}
I first compile Animal.java and put the Animal.class file into a directory
animals. I then compile MammalInt.java. If I do not put the Animal.class file in a animals directory it will not compile MammalInt.java . After I have both class files into the animals directory I do java animals/MammalInt and get the error: cannot find or load main class. I also have doe java MammalInt and get the same error. This is really frustrating. Please help.
When compiling (a set of files) you need to use the path.So use /
javac animals/*.java
When running the Java class, you need to specify the Java name of the class.
In your case this is done as follows:
java animals.MammalInt
This says you want the class MammalInt in the package animal. Depending on your installation you also need to add your current directory to your classpath (this is where java looks for .class files), resulting in:
java -cp . animals.MammalInt
Note that you run all commands from the root of your source code tree. This means the directory that contains the directories for your packages. So if you have the following direcotries:
project/
project/animals/
project/animals/Animal.java
Then run the commands from the project/ directories.
I have two top-level classes; each has an inner class with the same name:
**A.java**
public class A
{
}
class TestCase
{
}
**B.java**
public class B
{
}
class TestCase
{
}
My expectation is that I will wind up with four class files, including A$TestCase.class and B$TestCase.class, which is what I get when I compile from the command line. Eclipse, however, just creates TestCase.class, and declares that "The type TestCase is already defined" when I try to compile B.java.
Is there an Eclipse option that I can set to produce (what I believe is the standard) A$TestCase.class and B$TestCase.class?
Thanks.
By the way, I am using Luna:
Version: Luna Release (4.4.0)
Build id: 20140612-0600
Both versions of TestCase are top level classses. You need to create inner classes
public class A {
class TestCase {
}
}
It doesn't do this for me. It creates an A$TestCase.class and a B$TestCase.class, as it should.
But this is only when they're actually inner classes... in your case, they're not really inner classes at all.
TestCase is not an inner class as you might think, and this is why formatting code is essential when coding. check this
Imagine that I have two classes (shown below). Now imagine that I am compiling them using javac.exe from the command line. They won't compile because class A needs class B's methods to exist and vice versa. Is there any trick to getting them to compile from the command line? (Eclipse can compile this no problems!)
I should add they are both currently in two separate .java files.
public class A {
public void doAWork() { /* A work goes here. */}
public void doBWork() { new B().doBWork(); }
}
public class B {
public void doBWork() { /* B work goes here. */}
public void doAWork() { new A().doAWork(); }
}
It looks like your issue is elsewhere.
I can perfectly compile the code in Java 1.5, 1.6 and 1.7 with the following command:
javac A.java B.java
Even providing a single file name works perfectly, since B.java is in the same directory:
javac A.java
Are you sure the two files are placed in appropriate directories?