I want to create a Java IPC server module (with Jigsaw) which has two packages:
com.example.ipc.backend
com.example.ipc.backend.api
in my module-info.java I have the following export:
module ipclib {
exports com.example.ipc.backend.api;
}
I can import this module in my JavaFX GUI module without problems, but I'm having a problem creating a class inside the api module.
I have one interface in this class which some class in the GUI module should implement to register itself for changes in the IPC module (e.g. when a client connects to the IPC server):
public interface IpcCallback {
void clientConnected(Client client);
}
The class which implements this interface should then receive a Client with the information about the connected client. This Client class also internally holds a reference to the thread which holds the socket to the client.
public class Client {
private IpcConnection connection; //IpcConnection is from com.example.ipc.backend
public Client(IpcConnection connection) {
this.connection = connection;
}
}
My problem is now that I want to create an instance of Client in the non-exported backend module, whenever a new connection is created. How can I make the constructor to be only accesible within the module, without making it public?
If I make the constructor public, IntelliJ offers to use the constructor to create a new Client object in the GUI module, but does not have access to the IpcConnection class. It offers a quick fix to export the backend module, but this is not what I want when exporting the api.
Therefore, I wonder if this is still “allowed”, because the Java compiler compiles this without any warnings and problems, and it is just a problem of IntelliJ. Or shouldn't this be done like this?
But if this is not the allowed way to do so, I wonder why the module system actually allows exporting only some packages, as there will always be a boundary between exported packages and not-exported packages (only except if the not-exported classes are called from within the exported class, but not the other way round).
Minimal project
Module 'backend'
// backend/src/main/java/module-info.java
module ipclib {
exports com.example.ipc.backend.api;
}
// backend/src/main/java/com/example/ipc/backend/IpcConnection.java
package com.example.ipc.backend;
public class IpcConnection {
}
// backend/src/main/java/com/example/ipc/backend/api/Client.java
package com.example.ipc.backend.api;
import com.example.ipc.backend.IpcConnection;
public class Client {
private IpcConnection connection;
public Client(IpcConnection connection) {
this.connection = connection;
}
public String hello() {
return "Hello";
}
}
// backend/src/main/java/com/example/ipc/backend/api/IpcCallback.java
package com.example.ipc.backend.api;
public interface IpcCallback {
void clientConnected(Client client);
}
Module 'gui'
// gui/src/main/java/module-info.java
module gui {
requires ipclib;
}
// gui/src/main/java/com/example/ipc/gui/App.java
package com.example.ipc.gui;
import com.example.ipc.backend.api.Client;
import com.example.ipc.backend.api.IpcCallback;
public class App implements IpcCallback {
public static void main(String[] args) {
}
#Override
public void clientConnected(Client client) {
System.out.println(client.hello());
}
}
I think, this is not possible in java. You can not declare an interface that is "visible in namespace A and all its sub-namespaces").
In contrast to .net, Java does not really know about the "internal" principle.
If you just omit the word public on an interface or class definition, this element is only visible inside it's current package.
But this is not recursive, as it is in .net (where you create an internal object which is visible only inside the current project, no matter which subfolder or namespace).
In Java, the object is only visible inside its current package (i.e. the very same namespace). Sub-namespaces are not included. Neither are parent namespaces.
If I understood correctly you have subpackages A and B, and only A is made public. A has a class C that has a constructor that should be called from B but not be made public.
I think your best option is to make class C (Client) implement and interface that is public. So the interface class can be in the public package and the actual implementation can be in the non-public package.
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 would like to be able to add a file with the java structure and extension into my program to an arraylist via outside the actual program directory/jar.
Ex,
Test.java, located at C:\Users\user\Desktop\Test.java (Outside the jar)
public class Test extends Object {
public Test() {}
public void someMethod() {}
}
MyProgram.java
import java.util.ArrayList;
public class MyProgram extends Object {
public MyProgram() {}
public void readIn() {
ArrayList<Object> list = new ArrayList<Object>();
list.add(Test.java);
}
}
Obviously a lot more will have to be done but hopefully you understand the point.
Read In Test.java -> Convert it somehow so it's added to the arraylist due to it's extension. So if the extension was Family instead of Object, the arraylist would be ArrayList instead and Test extends Family.
Edit
As stated by a comment, this is an approach to a plugin mechanism.
The answer to this question stems from Seelenvirtuose's suggestion along with crick_007. To access classes outside the class path, simply create a ClassLoader and load the class in.
You must also use an interface to interact between the two classes, also knowing what methods are provided. Lastly, packaging must also be the same or else you'll get errors such as
PACKAGENAME.CLASS cannot be cast to PACKAGENAME.CLASS even if the class has the same name as in your program (A test I tried)
I have two questions:
1) Is there a way to extend of class A from external file ? how?
2) I am building one class of my custom methods ( to use globally, in all my projects). Here is phseudo-code:
package MyFunctions;
import Twitter.profile;
public class MyFuncs{
public String externalProfile1() { return Twitter.profile.TwitterUrl(); }
}
I want Is there a way to include that file in all my projects, and avoid IDE errors, as I should be able to use any when one of the above functions in my projects... The problem is that the Twitter.Profile classes are not included in all my projects, and whenever happens so - it see error in IDE("cannot find symbol method")...
how to solve the problem?
Question 2:
Just make sure all of your functions in your library are written statically:
public class MyFuncs{
public static String externalProfile1(String link) { return TwittUrl() + "/profile"; }
public static String externalProfile2(String link) { return YahooUrl() + "/profile"; }
}
And then import that class in your project files that you'll be using your library in. Then you can easily call the functions in your library. Alternatively, you can avoid importing the library in every other file and instead call the functions in a static way:
MyFuncs.externalProfile1("link");
As for TwittUrl(), if it doesn't require to be in a separate Class, then refactor it and put it in MyFuncs class; otherwise you can make TwittUrl() and YahooUrl() methods static in their own class.
I have several classes which implement two interfaces. All of them implement the BaseInterface and some other interface which is specific to them.
I want to be able to use the loadClass method below to instantiate classes which are referred to in a .properties file and call the common method they all contain (because they implement BaseInterface).
public interface BaseInterface {
public void doBase();
}
public interface SpecificInterface extends BaseInterface {
public void doSpecific();
}
public class SpecificClass implements SpecificInterface {
public void doBase() { ... }
public void doSpecific() { ... }
}
public class LoadClass() {
private PropertiesLoader propertiesLoader = new PropertiesLoader();
public <C extends BaseInterface> C loadClass(String propertyName) {
Class<C> theClass;
// Load the class.
theClass = propertiesLoader.getPropertyAsClass(propertyName);
// Create an instance of the class.
C theInstance = theClass.newInstance();
// Call the common method.
theInstance.doBase();
return theInstance;
}
}
Unfortunately, when I run the code:
loadClassInstance.loadClass("SpecificClass");
I get the following exception:
Exception in thread "main" java.lang.ClassCastException:
SpecificClass cannot be cast to BaseInterface
at LoadClass.loadClass
Any ideas how I would solve this issue?
Many Thanks, Danny
Java's Service Provider Interface (SPI) libraries allow you to load classes with public parameterless constructors dynamically based on the interfaces they implement, and it's all done through the use of META-INF/services.
First, you'll need the interface:
package com.example;
public interface SomeService {
String getServiceId();
String getDisplayName();
}
Then when you need them, you can load them using Java's ServiceLoader class, which implements Iterable:
ServiceLoader<SomeService> loader = ServiceLoader.load(SomeService.class);
for (SomeService serv : loader) {
System.out.println(serv.getDisplayName());
}
Then when you have 1 or more implementing classes on your classpath, they register themselves in META-INF/services. So if you have the implementation:
package com.acme;
public class SomeImplementation implements SomeService {
// ...
public SomeImplementation() { ... }
// ...
}
Note that this class needs a default no-args constructor, this is not optional.
You register it with the class loader by creating a file in META-INF/services in your classpath (such as in the root of your jar) with the following properties:
The name of the file is the fully qualified class name of the interface, in this case, it's com.example.SomeService
The file contains a newline-separated list of implementations, so for the example implementation, it would contain one line: com.acme.SomeImplementation.
And there you go, that's it. How you build your project will determine where you put the META-INF/services stuff. Maven, Ant, etc. all have ways of handling this. I recommend asking another question about your specific build process if you have any trouble adding these files to your build.
If you replace your code with below it works. I doubt that PropertiesLoader is doing something that is not supposed to be done.
Class<?> theClass;
// Load the class.
theClass = Class.forName("SpecificClass");
// Create an instance of the class.
C theInstance = (C) theClass.newInstance();
BaseInterface base = loadClass();//There is no problem in casting
Java program normally is loaded by system classloader. The classes which are referred to in a .properties file are loaded by a user-defined classloader. Classes loaded by different classloaders are considered different even if have same name and are loaded from same classfile. In your case, the interface BaseInterface loaded by system classloader is different from the BaseInterface loaded by
PropertiesLoader.
To fix this, PropertiesLoader should delegate loading of BaseInterface to system classloader. Typical way to do so is to use system classloader as a parent classloader for PropertiesLoader.
I am getting an exception and I can't find the reason of it.
The exception I get is :
java.lang.IllegalAccessError: tried to access method Connected.getData(Ljava/lang/String;)Ljava/sql/ResultSet; from class B
The method is public.
public class B
{
public void myMethod()
{
Connected conn = new Connected(); // create a connected class in order to connect to The DB
ResultSet rs = null; // create a result set to get the query result
rs = conn.getData(sql); // do sql query
}
}
public class Connected
{
public ResultSet getData(String sql)
{
ResultSet rs = null;
try
{
prepareConnection();
stmt = conn.createStatement();
stmt.execute(sql);
rs = stmt.getResultSet();
}
catch (SQLException E)
{
System.out.println("Content.getData Error");
E.printStackTrace();
}
return rs;
}
i am using apache tomcat 5.5.12
and JAVA 1.6
This happens when accessing a package scoped method of a class that is in the same package but is in a different jar and classloader.
This was my source, but the link is now broken. Following is full text from google cache:
Packages (as in package access) are scoped per ClassLoader.
You state that the parent ClassLoader loads the interface and the child
ClassLoader loads the implementation. This won't work because of the
ClassLoader-specific nature of package scoping. The interface isn't visible to
the implementation class because, even though it's the same package name,
they're in different ClassLoaders.
I only skimmed the posts in this thread, but I think you've already discovered
that this will work if you declare the interface to be public. It would also
work to have both interface and implementation loaded by the same ClassLoader.
Really, if you expect arbitrary folks to implement the interface (which you
apparently do if the implementation is being loaded by a different
ClassLoader), then you should make the interface public.
The ClassLoader-scoping of package scope (which applies to accessing package
methods, variables, etc.) is similar to the general ClassLoader-scoping of
class names. For example, I can define two classes, both named com.foo.Bar,
with entirely different implementation code if I define them in separate
ClassLoaders.
Joel
You are almost certainly using a different version of the class at runtime to the one you expect. In particular, the runtime class would be different to the one you've compiled against (else this would have caused a compile-time error) - has that method ever been private? Do you have old versions of the classes/jars on your system anywhere?
As the javadocs for IllegalAccessError state,
Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed.
I'd definitely look at your classpath and check whether it holds any surprises.
This happened to me when I had a class in one jar trying to access a private method in a class from another jar. I simply changed the private method to public, recompiled and deployed, and it worked ok afterwards.
I was getting this error on a Spring Boot application where a #RestController ApplicationInfoResource had a nested class ApplicationInfo.
It seems the Spring Boot Dev Tools was using a different class loader.
The exception I was getting
2017-05-01 17:47:39.588 WARN 1516 --- [nio-8080-exec-9]
.m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused
by Handler execution:
org.springframework.web.util.NestedServletException: Handler dispatch
failed; nested exception is java.lang.IllegalAccessError: tried to
access class com.gt.web.rest.ApplicationInfo from class
com.gt.web.rest.ApplicationInfoResource$$EnhancerBySpringCGLIB$$59ce500c
Solution
I moved the nested class ApplicationInfo to a separate .java file and got rid of the problem.
If getData is protected then try making it public. The problem could exist in JAVA 1.6 and be absent in 1.5x
I got this for your problem. Illegal access error
I was getting same error because of configuration issue in intellij.
As shown in screenshot.
Main and test module was pointing to two different JDK. (Press F12 on the intellij project to open module settings)
Also all my dto's were using #lombok.Builder which I changed it to #Data.
From Android perspective:
Method not available in api version
I was getting this Issue primarily because i was using some thing that is not available/deprecated in that Android version
Wrong way:
Notification.Builder nBuilder = new Notification.Builder(mContext);
nBuilder.addAction(new Notification.Action(android.R.drawable.ic_menu_view,"PAUSE",pendingIntent));
Right way:
Notification.Builder nBuilder = new Notification.Builder(mContext);
nBuilder.addAction(android.R.drawable.ic_media_pause,"PAUSE",pendingIntent);
here Notification.Action is not available prior to API 20 and my min version was API 16
Just an addition to the solved answer:
This COULD be a problem with Android Studio's Instant Run feature, for example, if you realized you forgot to add the line of code: finish() to your activity after opening another one, and you already re-opened the activity you shouldn't have reopened (which the finish() solved), then you add finish() and Instant Run occurs, then the app will crash since the logic has been broken.
TL:DR;
This is not necessarily a code problem, just an Instant Run problem
In my case the problem was that a method was defined in some Interface A as default, while its sub-class overrode it as private. Then when the method was called, the java Runtime realized it was calling a private method.
I am still puzzled as to why the compiler didn't complain about the private override..
public interface A {
default void doStuff() {
// doing stuff
}
}
public class B {
private void doStuff() {
// do other stuff instead
}
}
public static final main(String... args) {
A someB = new B();
someB.doStuff();
}
In my case I was getting this error running my app in wildfly with the .ear deployed from eclipse. Because it was deployed from eclipse, the deployment folder did not contain an .ear file, but a folder representing it, and inside of it all the jars that would have been contained in the .ear file; like if the ear was unzipped.
So I had in on jar:
class MySuperClass {
protected void mySuperMethod {}
}
And in another jar:
class MyExtendingClass extends MySuperClass {
class MyChildrenClass {
public void doSomething{
mySuperMethod();
}
}
}
The solution for this was adding a new method to MyExtendingClass:
class MyExtendingClass extends MySuperClass {
class MyChildrenClass {
public void doSomething{
mySuperMethod();
}
}
#Override
protected void mySuperMethod() {
super.mySuperMethod();
}
}
I was getting similar exception but at class level
e.g. Caused by: java.lang.IllegalAccessError: tried to access class ....
I fixed this by making my class public.