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 am trying to use Proguard to keep my private fields, but it won't work.
I stole most of this from Proguard keep classmembers because that question is similar to what I'm asking, and also followed this link How to tell ProGuard to keep private fields without specifying each field
But it still doesn't work.
I want to make a library for another company and still keep my access level modifiers fields and methods.
Proguard:
-keepclassmembers class com.example.mylibrary.Bedika {
private <fields>;
}
-keep class com.example.mylibrary.Bedika {
*;
}
My AAR library
public class Bedika {
private String stam;
public Bedika(String stam) {
this.stam = stam;
}
public void print() {
System.out.println(stam);
}
}
output after Proguard:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.example.mylibrary;
public class Bedika {
public String stam;
public Bedika(String var1) {
this.stam = var1;
}
public void print() {
System.out.println(this.stam);
}
}
It seems like R8 is causing this issue and not Proguard.
Go into gradle.properties, and set android.enableR8=false. Next time you build, it will use Proguard.
R8 is Google's answer to Proguard and in the recent versions of The Android Gradle Plugin (3.4.0+) it defaults to R8's code shrinker/obfuscator. There are some pros and cons to using Google's version instead of Guardsquare's technology.
For more information, look at the documentation
You can usually add the #Keep annotation above the class or object (in Java or Kotlin). This is pretty self-explanatory, and will work.
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 know I'm throwing a pretty stupid question, but I promise I did try to search around the settings and around google and the webs and no luck, so I guess I should just ask.
I saw in quite a few open-source projects the following line:
if(DEBUG){
// do some logging
}
I perfectly understand what the line is doing, I just can't seem to repeat it.
There's no declaration of boolean DEBUG; anywhere in the code, and I couldn't figure out a place on the project properties to define a system wide variable to be replaced on the compiling (into byte code). And as far as I know, if it's a reference to a class constant it was supposed to be Log.DEBUG or something similar.
Can anyone solve this mystery for me?
thanks.
You really should look at the import section of the class.
It is probably a static import, like this :
A.java
public class A {
public static boolean DEBUG = false;
}
B.java
import static A.DEBUG;
public class B {
public void myMethod() {
if (DEBUG) {
// do something
}
}
}
You are in front of a public static field, look in import list and pick the original class or, use the inline help from Eclipse as said in comments
In Java, you can define multiple top level classes in a single file, providing that at most one of these is public (see JLS ยง7.6). See below for example.
Is there a tidy name for this technique (analogous to inner, nested, anonymous)?
The JLS says the system may enforce the restriction that these secondary classes can't be referred to by code in other compilation units of the package, e.g., they can't be treated as package-private. Is that really something that changes between Java implementations?
e.g., PublicClass.java:
package com.example.multiple;
public class PublicClass {
PrivateImpl impl = new PrivateImpl();
}
class PrivateImpl {
int implementationData;
}
Javac doesn't actively prohibit this, but it does have a limitation that pretty much means that you'd never want to refer to a top-level class from another file unless it has the same name as the file it's in.
Suppose you have two files, Foo.java and Bar.java.
Foo.java contains:
public class Foo
Bar.java contains:
public class Bar
class Baz
Let's also say that all of the classes are in the same package (and the files are in the same directory).
What happens if Foo refers to Baz but not Bar and we try to compile Foo.java? The compilation fails with an error like this:
Foo.java:2: cannot find symbol
symbol : class Baz
location: class Foo
private Baz baz;
^
1 error
This makes sense if you think about it. If Foo refers to Baz, but there is no Baz.java (or Baz.class), how can javac know what source file to look in?
If you instead tell javac to compile Foo.java and Bar.java at the same time, or if you had previously compiled Bar.java (leaving the Baz.class where javac can find it), or even if Foo happens to refer to Bar in addition to Baz, then this error goes away. This makes your build process feel very unreliable and flaky, however.
Because the actual limitation, which is more like "don't refer to a top-level class from another file unless it either has the same name as the file it's in or you're also referring to another class that's named the same thing as that file that's also in that file" is kind of hard to follow, people usually go with the much more straightforward (though stricter) convention of just putting one top-level class in each file. This is also better if you ever change your mind about whether a class should be public or not.
Newer versions of javac can also produce a warning in this situation with -Xlint:all:
auxiliary class Baz in ./Bar.java should not be accessed from outside its own source file
Sometimes there really is a good reason why everybody does something in a particular way.
My suggested name for this technique (including multiple top-level classes in a single source file) would be "mess". Seriously, I don't think it's a good idea - I'd use a nested type in this situation instead. Then it's still easy to predict which source file it's in. I don't believe there's an official term for this approach though.
As for whether this actually changes between implementations - I highly doubt it, but if you avoid doing it in the first place, you'll never need to care :)
I believe you simply call PrivateImpl what it is: a non-public top-level class. You can also declare non-public top-level interfaces as well.
e.g., elsewhere on SO: Non-public top-level class vs static nested class
As for changes in behavior between versions, there was this discussion about something that "worked perfectly" in 1.2.2. but stopped working in 1.4 in sun's forum: Java Compiler - unable to declare a non public top level classes in a file.
You can have as many classes as you wish like this
public class Fun {
Fun() {
System.out.println("Fun constructor");
}
void fun() {
System.out.println("Fun mathod");
}
public static void main(String[] args) {
Fun fu = new Fun();
fu.fun();
Fen fe = new Fen();
fe.fen();
Fin fi = new Fin();
fi.fin();
Fon fo = new Fon();
fo.fon();
Fan fa = new Fan();
fa.fan();
fa.run();
}
}
class Fen {
Fen() {
System.out.println("fen construuctor");
}
void fen() {
System.out.println("Fen method");
}
}
class Fin {
void fin() {
System.out.println("Fin method");
}
}
class Fon {
void fon() {
System.out.println("Fon method");
}
}
class Fan {
void fan() {
System.out.println("Fan method");
}
public void run() {
System.out.println("run");
}
}
Just FYI, if you are using Java 11+, there is an exception to this rule: if you run your java file directly (without compilation). In this mode, there is no restriction on a single public class per file. However, the class with the main method must be the first one in the file.
1.Is there a tidy name for this technique (analogous to inner, nested, anonymous)?
Multi-class single-file demo.
2.The JLS says the system may enforce the restriction that these secondary classes can't be referred to by code in other compilation units of the package, e.g., they can't be treated as package-private. Is that really something that changes between Java implementations?
I'm not aware of any which don't have that restriction - all the file based compilers won't allow you to refer to source code classes in files which are not named the same as the class name. ( if you compile a multi-class file, and put the classes on the class path, then any compiler will find them )
Yes you can, with public static members on an outer public class, like so:
public class Foo {
public static class FooChild extends Z {
String foo;
}
public static class ZeeChild extends Z {
}
}
and another file that references the above:
public class Bar {
public static void main(String[] args){
Foo.FooChild f = new Foo.FooChild();
System.out.println(f);
}
}
put them in the same folder. Compile with:
javac folder/*.java
and run with:
java -cp folder Bar
According to Effective Java 2nd edition (Item 13):
"If a package-private top-level class (or interface) is used by only
one class, consider making the top-level class a private nested class
of the sole class that uses it (Item 22). This reduces its
accessibility from all the classes in its package to the one class
that uses it. But it is far more important to reduce the accessibility
of a gratuitously public class than a package-private top-level class:
... "
The nested class may be static or non-static based on whether the member class needs access to the enclosing instance (Item 22).
No. You can't. But it is very possible in Scala:
class Foo {val bar = "a"}
class Bar {val foo = "b"}