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.
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
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 am creating a package com.XXXX
Inside that I am declaring many classes in a java file (default - not public)
let is be like:
class A{}
class B{}
class C{}
I am importing com.XXXX in another file
I am unable to use these classes that are inside the package, as they are not public.
So I am pushing to a state of creating individual files for each classes.
Every class is just a small structure, where it doesn't have any extra function. So I thought of keeping them in single file. So I can't declare classes as public
Is there any way to use all classes without splitting them into separate files?
If (somehow) it makes sense to group these classes together, then you could put them inside a wrapper class as static inner classes, for example:
package com.somewhere;
public class Utils {
public static class DateUtils {
public static Date today() {
return new Date();
}
}
public static class FilenameUtils {
public static String stripExtension(String path) {
return path.substring(0, path.lastIndexOf("."));
}
}
}
Then, you will be able to import these elsewhere:
package com.elsewhere;
import com.somewhere.Utils;
public class Task {
Date today = Utils.DateUtils.today();
}
This is because the default java access modifier is package private. When you create the classes without an access modifier they become accessible only within the package.
If you don't want to expose it outside the jar then rename your package to be com.internal.XXXX. When you put the internal keyword that package wont be available outside the jar even thought your classes inside the package would be public.
If you want to have more than one class in the same file, you can use Nested Classes.
Please, take a look at:
https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Example:
class OuterClass {
...
class NestedClass {
...
}
}
You can then refeer to OuterClass.NestedClass from another package
I am just testing dynamic class load and am doing this:
package P1;
public class Class1
{
public static void main(String[] args)
{
Bird myBird = null;
String myClassName = "P2.Bird";
Class x = Class.forName(myClassName);
myBird = (Bird)x.newInstance();
}
}
Bird is a class from package P2, and Class1 is from P1. What should I add in the code to make this work, as the String myClassName... line shows an error (class not found). I tried the same code after moving Bird in package P1, even then it doesn't work.
Related question: Why would someone use dynamic class load, does it have any advantages? It's much simpler(at least for me at first glance) to just use the "new" operator for static class loading, and in that case I know how to refer the class from a different package. Many thanks!
For the answer to your first question try mentioning full Package name. I have tried it and it works
Your Bird class provides a default public constructor with no arguments?
Dynamic class loading can be useful for example to specify the class you want to use in a configuration file (you will come across that if you ever use log4j, or other libraries that allow the use of your own implementation to one of their interfaces). In that case, the library does not know about which class you will use, and you don't have to write code to initialise the library (which would be the alternative to dynamic class loading, but which is less convenient)