I am trying to recompile a JAVA8 code in JAVA11.
Getting below compilation errors.
error: reference to Module is ambiguous
private Module module;
both interface com.module.Module in com.module and class java.lang.Module in java.lang match
Being new to the Java not able to fully understand the root cause. Any information will be of great help.
both interface com.module.Module in com.module and class
java.lang.Module in java.lang match
The error is mostly because of the new class java.lang.Module introduced in Java-9.
Just use the fully qualified name while referencing the interface/class that you've defined as:
private com.module.Module module;
Alternatively, as pointed out by Alan and Holger in comments and from the release notes of Java-9, you can explicitly specify the import for your Module class as :
import com.module.Module;
Related
I have written an annotation processor that generates a builder class for my classes annotated with #DataBuilder
#Target(AnnotationTarget.CLASS)
#Retention(AnnotationRetention.SOURCE)
annotation class DataBuilder
My classes annotated with this annotation are located in the com.my.package.model package and the generated builder class is also located in the same package com.my.package.model but in the generated directory of course build/generated/source/kapt/debug/com/my/package/model/MyModelBuilder.kt, I can use these generated classes fine inside of my model classes(written in Kotlin)
BUT I can NOT use the generated MyModelBuilder Kotlin class inside of a java class as a class member
package com.my.package.home;
import com.my.package.model.MyModelBuilder;
public class Home {
MyModelBuilder builder; // <=== AS recognizes the class, but I'm having an compilation issue
}
Android Studio recognizes the class, but I’m having this compilation issue
com/my/package/home/Home.java:4: error: cannot find symbol
MyModelBuilder builder;
^
symbol: class MyModelBuilder
location: class Home
it’s weird because I can use this generated builder class only inside of methods, this code compiles fine:
package com.my.package.home;
import com.my.package.model.MyModelBuilder;
public class Home {
public void hello() {
MyModelBuilder builder;
}
}
could somebody here help me to understand this behavior and how to fix this? In advance, thanks!
UPDATE
I just created this repo with the necessary code to replicate the issue
https://github.com/epool/HelloKapt
The project works fine after cloning and running, to replicate the issue please un-comment this line https://github.com/epool/HelloKapt/blob/master/app/src/main/java/com/nearsoft/hellokapt/app/MainActivity.java#L13
Note: If I convert my MainActivity.java class to Kotlin(MainActivity.kt) the issues is NOT reproducible and works fine, but I don’t want to do so due to some project limitations so far
Kotlin Issue: https://youtrack.jetbrains.net/issue/KT-24591
Looking at your Github project, I notice that you don't declare a dependency on kotlin-stdlib-jdk7 in the app module. When I build the module, compiler emits the following warnings:
warning: unknown enum constant AnnotationTarget.CLASS
reason: class file for kotlin.annotation.AnnotationTarget not found
warning: unknown enum constant AnnotationRetention.SOURCE
reason: class file for kotlin.annotation.AnnotationRetention not found
warning: unknown enum constant AnnotationTarget.CLASS
reason: class file for kotlin.annotation.AnnotationTarget not found
Since kotlin-stdlib-jdk7 is declared as implementation in the annotations module, the app module doesn't see it as a transitive dependency, that might be the reason why compilation fails. To fix it, you should probably declare the correct dependency in the app module, or at least use apiElements scope for kotlin-stdlib-jdk7 in annotations.
The fact that the IDE doesn't notify you that compilation failed might be a tools bug, but there's definitely no underlying Kotlin compiler issue.
OK so this is some kind of theoretical question for you guys.
I am experimenting with cglib's Enchancer - creating a proxy for a class.
My code is running in a Felix OSGi container.
The hierarchy looks kind of similar to that:
// Bundle A;
// Imports-Package: javax.xml.datatype
// Exports-Package: a.foo
package a.foo;
public class Parent {
protected javax.xml.datatype.XMLGregorianCalendar foo;
... -> getter/setter;
}
// Bundle B
// Imports-Package: a.foo
// DOES NOT IMPORT PACKAGE javax.xml.datatype !!!
package b.bar;
import a.foo.Parent;
public class Child extends Parent {
protected String bar;
... -> getter/setter;
}
// Bundle B
// Code extracted from https://github.com/modelmapper/modelmapper/blob/master/core/src/main/java/org/modelmapper/internal/ProxyFactory.java#L59
public Child enchance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Child.class);
enhancer.setUseFactory(true);
enhancer.setUseCache(true);
enhancer.setNamingPolicy(NAMING_POLICY);
enhancer.setCallbackFilter(METHOD_FILTER);
enhancer.setCallbackTypes(new Class[] { MethodInterceptor.class, NoOp.class });
try {
return enhancer.createClass();
} catch (Throwable t) {
t.printStackTrace();
}
}
From OSGi point of view - the two bundles - Bundle A and Bundle B are fully functional.
The package imports/exports are bnd generated. Although BundleA does not import explicitly the javax.xml.datatype package - I can create instances of Child without any problem.
So far so good.
But when I try to call the enchance() method and create a Child proxy - cglib throws a NoClassDefFoundError: javax.xml.datatype.XMLGregorianCalendar
OK, I get this - BundleB's classloader indeed cannot load this class and in fact - cglib's Enchancer seems to be using BundleB's classloader (Child's class type classloader) in order to create the proxy.
On the other hand - for handling modularity the OSGi container is doing the so called classloading delegation - instead of BundleB's classloader, the OSGi runtime delegates the loading of the parent class Parent to BundleA's classloader, which knows how to load all of its fields.
This is why BundleB does not need to explicitly import the javax.xml.datatype package and does not need to know how to load the XMLGregorianCalendar class and still be able to work with Child objects.
I was wondering - isn't such "delegating" approach suitable in the cglib's use case as well?
Please note that I don't know ANYTHING about byte code manipulation and that might sound like a very stupid question to some.
But I really don't understand - why isn't cglib able to delegate loading of the Parent to Parent's own classloader?
Is such mechanism really not available in cglib? Why? Is cglib not used in combination with OSGi? If so then why?
The Child class does not need to import javax.xml.datatype so long as it does not access the javax.xml.datatype.XMLGregorianCalendar field and you are just using the Child class in the normal way. However in order to generate a proxy class, CGLib will need to have visibility of the internals of the full inheritance hierarchy including the javax.xml.datatype.XMLGregorianCalendar in order to generate the bytecode for the new type. Therefore an import of the package will be required.
Unfortunately bnd cannot predict that you will be doing bytecode generation on the Child class so it does not add the import of javax.xml.datatype – it only add the imports required for normal usage.
In general it is a bad idea to inherit from a class imported from another bundle. Java inheritance creates a very tight coupling from the subclass to the superclass, which means you are exposed to the internals of the superclass.
To your last question: CGLib is fairly widely used in OSGi for things like mocking objects during testing. It is less used in production because there is nearly always a better solution than bytecode generation, such as proper usage of the service registry.
I tried combining the OSGi Class Loader Bridge idea that is described here:
https://www.infoq.com/articles/code-generation-with-osgi
... that solves a similar problem with code generation frameworks running within OSGi, with another idea that came to me recently.
The idea is to keep track of class loaders of class types that are found in the parent type hierarchy of the user's type. We can later use these class loaders as fallback for loading types that are otherwise unknown to the Bundle's class loader of the user's type.
We can then tell CGLIB's Enhancer to use this new class loader for resolving.
The idea is presented here:
https://github.com/modelmapper/modelmapper/pull/294
I would love to hear the opinion of experienced OSGi specialists about this though.
But so far this seems to work.
Until proven wrong, I accept my own answer.
We are working on java classes in order to customize it. Before this customization, we just want to check compile/decompile process of existing java jar file (MMC.jar).
We collected all java class file under MMC.jar using jd-gui tool
So when we were compiling the existing MMC.jar (without customization) it is giving attached 6 errors
./com/mmc/model/acknowledgement/package-info.java:7: error: illegal start of
type abstract interface package-info {}
^
./com/mmc/model/acknowledgement/package-info.java:7: error: = expected
abstract interface package-info {}
^
./com/mmc/model/customer/package-info.java:7: error: <identifier> expected
abstract interface package-info {}
^
./com/mmc/model/customer/package-info.java:7: error: illegal start of type
abstract interface package-info {}
^
./com/mmc/model/customer/package-info.java:7: error: = expected
abstract interface package-info {}
^
6 errors
This is the content of package-info java file
package com.mmc.model.customer;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
#XmlSchema(namespace="http://www.iflex.com/mmc/model/customer",
elementFormDefault=XmlNsForm.QUALIFIED)
abstract interface package-info {}
Regards
Ali
The reason you've got compilation error is package-info is not allowed identifier. You cannot name objects like classes, interfaces, variables, etc, with - character. See this answer for more detail Naming rules.
But the problem is that you use package info file in wrong way. The aim of package-info.java file is to add brief description of package in javadoc: what the purpose of this package, responsibilities and contents. You shouldn't declare any classes or interface here. All you need to write in this file is package name in which this file located and package summary javadoc. A #sidgate comment refers to a good answer about package info file responsibility.
How does a Java ClassLoader load imports like import java.util.*? I am asking, because I have a custom classloader which sometimes is asked to load a package instead of a class. Example:
public Class<?> loadClass(String className) throws ClassNotFoundException
{
System.out.println(className);
return parent.loadClass(className);
}
Example output:
org.test.model.User
org.test.model
org.test.model
So it seems like the whole package is requested (may be due to import org.test.model.* ?) I am not sure if the imports are causing this (and how to handle it) or if everything is fine and should be this way. Thanks in advance!
Note: This question seems to be the root of my actual problem.
EDIT
Out of the answer below I do understand that classes are loaded when referenced and the import statement is not what is important. Anyhow, why are packages (like "org.test.model" in the example above) being loaded? Or what would such a request mean?
'import' is simply syntactic sugar. When your code gets compiled to bytecode, all classes are referenced by their complete package.name
The thing here to understand is that ClassLoader don't resolve imports,they resolve classes lazily as they are referenced .They may be resolved eagerly by using Class.forName(String className).
So basically if you are using import myclasses.unusedPackage.* ,it doesn't go for resolving all the classes present in the package but will only load a Class as it is referenced.
I tried to create a custom class String in java.lang package in my eclipse workspace.
initially I suspected that a same class in same package can not be created but to my utter surprise I was able to create a class (String) in same package i.e. java.lang
Now I am confused
1) why is it possible and
2) what can be the reason if that is allowed.
3) what will be the use if this type of creation of java classes is allowed in Java.
You can create a new class in java.lang package. If it was forbidden how Oracle developers would be able to develop Java at all? I am sure they use the same javac as we do.
But you will not be able to load it, because java.lang.ClassLoader (that any classloader extends) does not allow it, every class being loaded goes through this check
...
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("Prohibited package name: " + name.substring(0, name.lastIndexOf('.')));
}
...
so you will end up in something like
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:649)
at java.lang.ClassLoader.defineClass(ClassLoader.java:785)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at Test1.main(Test1.java:11)
As for classes that shadow existing classes like your java.lang.String they cannot be loaded because the System ClassLoader (default one) uses "parent first" strategy, so java.lang classes will be loaded from rt.jar with bootstrap classloader. So you will need to replace String.class in rt.jar with your version. Or override it using -Xbootclasspath/p: java option which prepends paths to bootstrap class loader search paths. So you can
1) copypaste real String.java content into your String.java
2) change a method, eg
public static String valueOf(double d) {
return "Hi";
}
and compile your String.java
3) create a test class
public class Test1 {
public static void main(String[] args) throws Exception {
System.out.println(String.valueOf(1.0d));
}
}
4) run it as
java -Xbootclasspath/p:path_to_your_classes Test1
and you will see
Hi
This is called class shadowing.
1.) It is possible because java classes are not statically linked, but linked at class load time.
2.) If it was not allowed, then the whole class loading would be a lot more difficult to achieve. Then for example you would also have to build your project against a specific Java version. because Java classes may change from version to version. This isn't going to be a maintainable approach.
3.) osgi makes use of this to be able to load different versions of the same bundle. Another common use case is to replace buggy classes in frameworks, where no other workaround is possible. However this technique should be used carefully, because errors might be hard to debug.
Please note that however shadowing classes in the java.* packages is not allowed, as this would break the Java security sandbox. So you are going to have problems at runtime.
Yes you can create the package with name java.lang and also Class named as String.
But you wont be able to run your String class.
1) why is it possible : Compiler will compile your class successfully.
2) what can be the reason if that is allowed : You have a valid name for your package and class so compiler doesn't complain.
3) what will be the use if this type of creation of java classes is allowed in Java : But there is not much use of this String class. Bootstrap class loader will load class from the sun's java.lang package. So your custom String class will not get loaded and hence it fails during run.
Bootstrap class loader is part of JVM implementation and it loads the classes of Java API (which includes java.lang.String). Also for each class which gets loaded, JVM keeps track of which class loader whether bootstrap or user-defined - loaded the class. So any attempt to load a custom String class will fail as String class is already loaded.