I am working on a project that is having a layered Architecture.
I have a interface ABC and in that interface I have a enum XYZ
For ex
public interface ABC {
public enum XYZ {
CONSTANT1("SOMETHING"),
CONSTANT2("SOMETHING3");
final String name;
private TYPE(String name) {
this.name=name;
}
public String getName() {
return this.name;
}
}
}
I am compiling this using ant and using this jar file in other layer. In that layer I am trying to access it like
String name=ABC.XYZ.CONSTANT1.getName();
I am getting symbol not found error during compile. I verified classpath is set properly.
I am using ant v 1.8 and java 1.6.
Why I am getting this error ?
First of all, don't nest the enum in an interface. It's perfectly fine that it has its own source file named after the enum.
Second, I assume you mean XYZ instead of TYPE in your private constructor?
Last, you should be able to use it in that way, no matter if compiled via ant or within eclipse or directly using javac. Probably you have not compiled everything - the way you did it, there should be ABC.class (the interface), ABC$XYZ.class (the inner enum) and the class file of your calling class.
Related
I'm modifying someone else's code to implement a new functionality and I can't do it without changing the return of one of the functions. As I've said, this is not my code, so I can't change a single line of code.
The function itself is the following:
package me.Mohamad82.MineableGems.Core;
public class DropReader {
...
public DropReader() {}
public CustomDrop readCustomDrop(ConfigurationSection section, String mined, #Nullable String sectionNumber) {
...
}
}
And I'm trying to do something like this:
package com.rogermiranda1000.mineit;
public class DropReader extends me.Mohamad82.MineableGems.Core.DropReader {
public DropReader() {
super();
}
#Override
public CustomDrop readCustomDrop(ConfigurationSection section, String mined, #Nullable String sectionNumber) {
CustomDrop drop = super.readCustomDrop(section, mined, sectionNumber);
if (drop != null) {...}
return drop;
}
}
The problem is that I have no idea where to start. I can't change their code to call the other object, and I can't change the function call either.
The object is created every time (inside the functions that uses DropReader) so Reflection won't work, and searching I found something named Javassist but it won't work if the class is already loaded. I should be able to load by code before, but even with that I don't know if I'm approaching to the problem correctly, what do you think?
Edit: I'll try to explain better the situation. There's a class named Commands that runs the command new DropReader().readCustomDrop(section, mined, sectionNumber). The problem is that if section.getString("mine") != null I need to change the readCustomDrop return (I need to add an aditional property).
I can't change Commands's code, nor DropReader. Commands MUST get the modified object.
Edit2: It should work on both Java 8 and 17.
Probably the best way to do this is Java Instrumentation, but it was too complex for me so I did the following (assuming you have the .jar, and the .jar it's not already loaded):
Open the .jar as a Zip using ZipFile class
Send the .java to ClassFileToJavaSourceDecompiler (from JD-Core) and decompile it
Change the .java code
Compile the new code running javac with Runtime.getRuntime().exec (note: you'll probably need to add the dependencies using -classpath)
Add the compiled .java to the .jar
I wrote down a Enum class which could successfully compile, and then whenever I use the Enum class as a type of variable in the other class of the same package, the "cannot find symbol" would occur when compiling.
Here is the code for Enum:
package cards;
public enum CardType {
NIGHTMUSHROOM,DAYMUSHROOM,CIDER,BUTTER,PAN,BASKET,STICK
> }
And then I use the Enum in another class, I tried to import while the two pieces of code are in the same package so there is no use for the error.
package cards;
//import static cards.CardType;
public class Card{
protected CardType type;
protected String cardName;
public Card(CardType newType,String newName){
this.type = newType;
this.cardName = newName;
}
public CardType getType(){
return this.type;
}
public String getName(){
return this.cardName;
}
}
However when I compile Card class, I report the error message like below
I have looked at some of the questions about enum in the forum while they couldn't make sense for my code.
The CardType class's full name is cards.CardType (it's the package name, plus a dot, plus the classname). Hence, when javac is attempting to compile Card.java, it looks for the class cards.CardType. To find it, it scans the classpath roots for the path /cards/CardType.class.
It can't find this file, hence, error.
The 'root' that you need to make this work is the parent directory of whereever Card.java lives. After all, if you start at that path and 'dir' into cards and then look for CardType.class, that'll work. It's generally a good idea to stay in this 'root' instead of CDing into subdirs from there.
Hence:
cd /home/tianyue/projects/myawesomeproject
ls; -- prints: "cards"
ls cards; -- prints: "CardType.java Card.java"
javac cards/CardType.java
javac cards/Card.java
Will work fine unless you've been messing with settings and removed . as default path. You can always forcibly add it - javac -classpath . cards/Card.java instead. Or, much simpler:
javac cards/*.java
Note that most folks will use a build system such as gradle or maven, or an IDE, to take care of building projects. Once you involve multiple packages and dependencies, trying to command-line your way through a compilation process with just javac invokes gets real tedious.
Is it possible to change the name of a class retrieved using:Foo.class.getName() (or getSimpleName() or getCanonicalName()).
I know that those methods are part of java.lang.Class<T> the question itself is if there is a way to tell java.lang.Class<T> what is the name that I want it to display for my class.
I know that it "opens the door to tricky things" since that name is used by the reflection libraries to do "stuff" and bla bla bla. nevertheless I was wondering wether is posible to call Foo.class.getSimpleName() and get something like MyFoo.
All of this of course without string manipulation which is the last alternative I have.
Find the src.zip in your JDK. Extract java/lang/Class.java into some directory and modify getSimpleName() method. For example like this:
public String getSimpleName() {
return "MyName"; // return MyName for any class
}
Compile it normally with javac (you will get many warnings, ignore them). Remove all additional classes created like Class$1.class, leaving only java/lang/Class.class file. Put it into jar:
$ jar -c java >myclass.jar
Now prepend the bootstrap path with your new jar. For example, let's consider this test class:
public class Test {
public static void main(String[] args) {
System.out.println(Test.class.getSimpleName());
}
}
$ java Test
Test
$ java -Xbootclasspath/p:myclass.jar Test
MyName
I don't even want to explain how dangerous it is. Also according to the Oracle binary code license (supplemental term F) you cannot deploy your application this way.
You may try Powermock which according to their home page allows mocking final classes although it needs to use it's own class loader.
Other mocking frameworks that do not do byte code manipulation with custom class loaders such as Mockito and Easymock cannot work with classes that are final which java.lang.Class is.
How exactly is the Java compiler fetching code from other files (using "new" and "extends") without direct reference to those files (by only naming the classes)? is the compiler essentially reading all the Java files in the directory looking for relevant classes to include?
Example:
File 1:
public class Person {
public String name;
public Person(String name) {
this.name = name;
}
}
File 2:
public class Student extends Person {
...
...
Person you = new Person("foo");
When you reference a class called Person the compiler searches for a file called Person.class.
This search is done in each directory specified in the CLASSPATH (both the environment variable and the classpath specified in the arguments of java).
Note that the compiler first needs to know to what package a class belongs, so you can have two classes with the same name in different packages and still it will find the correct one (the one of the package you imported or that you fully qualified).
So if your class is actually: com.myorg.Person it will search in this classpath for a file:
com/myorg/Person.class
I am new to java and i am writing this code in notepad which is giving me errors.In netbeans although package is already defined.How to do this in notepad?
package A;
class A {
private String name;
protected String company="oracle";
A(String name) {
this.name = name;
System.out.println(name);
}
}
public class B extends A {
// A public class constant
public final static String st = "Public access modifiers";
B(String name) {
super(name);
}
void getCompany()
{
System.out.println(company);
}
}
package B;//getting class interface or enum expected
public class Application {
public static void main(String[] args) {
System.out.println(st);
B b=new B("Java");
b.getCompany();
}
}
You can not put different packages into the same source file... You have to create the appropriate folder structure, and separate Java source files for the sources in each package...
Also, to be able to reference classes from other packages, you have to import them appropriately, and make sure they are actually on the classpath both for compiling and running too......
Recommended reading
Java packages Wiki page
Java 7 package specification
Java Language Specification: import
package B;//getting class interface or enum expected
remove this line
Package declaration should be the first line of the source file.
You can not write 2 or more different packages with in the same source
The package statement should be the first line in the source file. There can be only one package statement in each source file, and it applies to all types in the file.
The PackageOrTypeName must be the canonical name (§6.7) of a package, a class type, an interface type, an enum type, or an annotation type.
That is what it is telling, and remove multiple declarations of package
And you should import the class B, When they both belongs to different packages.
import packagePath.B;
If a single-type-import declaration imports a type whose simple name is n, and the compilation unit also declares a top level type (§7.6) whose simple name is n, a compile-time error occurs.
Language Specification
Side note: Do not write multiple classes in a single java file. Later It's very hard to maintain the code.