Why aren't *AssertionStatus methods in a nested-class context complementary? - java

According to the documentation for the methods in question,
java.lang.Class#desiredAssertionStatus() states that it:
Returns the assertion status that would be assigned to
this class if it were to be initialized at the time this
method is invoked. If this class has had its assertion
status set, the most recent setting will be returned etc.
and then, in the API Note, it couches in an oracle worthy
of Croesus:
Note that this method is not guaranteed to return
the actual assertion status that was (or will be)
associated with the specified class when it was (or will
be) initialized.
java.lang.ClassLoader#setClassAssertionStatus(String, boolean)
states that it:
Sets the desired assertion status for the named top-level
class in this class loader and any nested classes
contained therein.
and, finally, it puts in a caveat:
If the named class is not a top-level class, this
invocation will have no effect on the actual assertion
status of any class.
In the context of these contracts, it could be demonstrated
that desiredAssertionStatus professes ignorance about
top-level-class and nested-class relations unless, despite
the above caveat, the assertion status has been explicitly
set for each nested class name.
For example,
package assertions;
class NestHost
{
static abstract class Base
{
private static boolean assertableStatus(Class<?> klass)
{
return klass.desiredAssertionStatus();
}
private static boolean assertableContext()
{
boolean assertable = false;
assert assertable = true;
return assertable;
}
void tryAsserting()
{
final String className = getClass().getName();
if (!assertableContext())
throw new IllegalStateException(className);
System.err.format("%s: assertion status: %b%n",
className,
assertableStatus(getClass()));
try {
assert false;
} catch (final AssertionError expected) {
System.err.format("%s: enabled assertions%n%n",
className);
return;
}
throw new IllegalStateException(className);
}
}
static final class A extends Base { }
static final class B extends Base { }
}
package assertions;
class NestedClassAssertionTests
{
static void assertWithImplicitStatusSettingOfA()
{
new NestHost.A().tryAsserting();
}
static void assertWithExplicitStatusSettingOfA(ClassLoader loader)
{
loader.setClassAssertionStatus(NestHost.A.class.getName(), true);
new NestHost.A().tryAsserting();
}
static void assertWithImplicitStatusSettingOfB()
{
new NestHost.B().tryAsserting();
}
static void assertWithExplicitStatusSettingOfB(ClassLoader loader)
{
loader.setClassAssertionStatus(NestHost.B.class.getName(), true);
new NestHost.B().tryAsserting();
}
public static void main(String[] args)
{
final ClassLoader loader = ClassLoader.getSystemClassLoader();
loader.clearAssertionStatus(); /* Discard `-da' and `-ea'. */
loader.setClassAssertionStatus(NestHost.class.getName(), true);
assertWithImplicitStatusSettingOfA();
assertWithExplicitStatusSettingOfA(loader);
assertWithImplicitStatusSettingOfB();
assertWithExplicitStatusSettingOfB(loader);
}
}
By launching the compiled (OpenJDK 17.0.4+8-Debian-1deb11u1)
entry-point class and observing its output, it could be
seen, with assertions enabled throughout, that the assertion
status needs to be explicitly set for each nested class.
Shouldn't desiredAssertionStatus and setClassAssertionStatus
be complementary in a nested-class context? In other words,
why doesn't the invocation of desiredAssertionStatus pan
out for the nested classes after setClassAssertionStatus
has been invoked for the top-level class?
Looking at the source (OpenJDK 17.0.4+8-Debian-1deb11u1)
of setClassAssertionStatus, there appears no distinct logic
for either top-level-class or nested-class names, on which
ClassLoader's own desiredAssertionStatus could have relied.
Has fulfilling the contract of setClassAssertionStatus
proved rather extravagant for desiredAssertionStatus to
share with, hence the latter's oracle?
(The desiredAssertionStatus method is casually resorted to
in an xUnit engine implementation I tinker at, whenever
clients wish to use assert statements in a test class and
a formal verification is sought as to whether assertion is
enabled.)

Related

How to prevent Lambda expressions defined in a Java agent break the application it is attached to?

If I declare this advice in my agent:
public static class SequenceAdvice {
#Advice.OnMethodEnter
static void enter(#Advice.This Object thiz,
#Advice.Origin Method method,
#Advice.AllArguments Object... args) {
StackWalker walker =
StackWalker.getInstance(RETAIN_CLASS_REFERENCE);
walker.forEach(sf ->
System.out.println(sf.getClassName() + "." + sf.getMethodName())
);
}
}
as javac compiles the lambda expression into a private method (at least in OpenJDK 11):
public class SequenceAgent$SequenceAdvice {
...
private static void lambda$enter$0(java.lang.StackWalker$StackFrame);
...
}
when the agent is attached to a program and the program is executed, it causes the program to crash:
Exception in thread "main" java.lang.IllegalAccessError:
class DemoController tried to access private method
SequenceAgent$SequenceAdvice.lambda$enter$0(
Ljava/lang/StackWalker$StackFrame;)V
(DemoController and SequenceAgent$SequenceAdvice
are in unnamed module of loader 'app')
at DemoController.getDemos(DemoController.java)
at DemoMain.main(DemoMain.java:13)
Ideally I prefer not to use objects instead of lambda expressions to workaround this:
public static class SequenceAdvice {
public static Consumer<StackWalker.StackFrame> SF_CONSUMER =
new Consumer<>() {
#Override
public void accept(StackWalker.StackFrame sf) {
System.out.println(sf.getClassName() + "." + sf.getMethodName());
}
};
#Advice.OnMethodEnter
static void enter(#Advice.This Object thiz,
#Advice.Origin Method method,
#Advice.AllArguments Object... args) {
StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE);
walker.forEach(SF_CONSUMER);
}
}
A custom permissive security policy does not seem to resolve this error:
grant {
permission java.security.AllPermission;
};
Is there a way to temporarily disable this category of security checks (e.g. "access to private method")?
You cannot use lambda expressions from an advice. The lambda expression will be a part of the advice class that is not exposed to the target class. Instead, you will need to define a utility class that defines the lambda expressions code in public methods and reference those methods as method references.
You must then either:
add this class to the bootstrap class loader via Instrumentation.
add this class to the class loader of the instrumented class via Byte Buddy's Injector.
This way, the references are available to the instrumented class and can be executed.

Invoke some code when VM load interface

In normal Java class, when VM load a class, it will invoke clinit method, so I wonder know when VM load a interface, can it invoke some code?
for example, class B implements A, new B(), VM invoke clinit of B, what will VM do with A, in A can I insert some code like System.out.println("hello")
Directly not, Java interfaces are not supposed to contain any code, even if you can now have default method. Following code will not compile:
interface Foo {
init {
System.out.println("Loading Foo...");
}
}
However, interfaces can contain static fields:
interface Foo {
static class FooLoader {
private static Object init() {
System.out.printf("Initializing %s%n", Foo.class);
}
}
Object NULL = FooLoader.init();
}
Again, it may work BUT:
through Reflection, it's still possible to invoke init() method, so it can be called twice
code isn't really called at load time but at init time. To understand, what I mean check this simple main:
System.out.println("START");
System.out.println(Foo.class);
System.out.println("END");
As long as you don't access static members, Java interfaces are not initialized (See §5.5 of JVM Specification)
So, to truely catch load time, you can use a custom class loader, or instrumentation API.
Having static {} block in interfaces isn't possible. But if you are really certain that you need to invoke some code when loading interface you can use custom classloader which will hook your interface loading and perform some action on that
Here is an example:
static class MyClassLoader extends ClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("test.Test1")) {
... do whatewer you need on loading class/interface...
}
return getParent().loadClass(name);
}
}
}
How to replace classes in a running application in java ?
Also there is very usefull tutorial: https://zeroturnaround.com/rebellabs/reloading-objects-classes-classloaders/
As mentioned in another answers, you cannot have static section in interfaces. However you can have static methods and static final fields. You can combine both for debugging purposes.
interface TestInterface {
int dummy = init();
static int init() {
System.out.println("Loaded TestInterface");
return 1;
}
}

Instantiate Java lambda function by name

I would like to create a lambda function in Java 8, get it's classname and then later instantiate the function again from its classname.
This is what I try:
import java.util.function.Consumer;
public class SimpleLambda
{
public static void call(String aLambdaClassName, String aArg) throws Exception
{
Class<Consumer<String>> lClass = (Class<Consumer<String>>) Class.forName(aLambdaClassName);
Consumer<String> newlamba = lClass.newInstance();
newlamba.accept(aArg);
}
public static void main(String[] args) throws Exception
{
{
// Attempt with a static method as lambda
Consumer<String> lambda = Host::action;
String classname = lambda.getClass().getName();
call(classname, "Hello world");
}
{
// Attempt with a locally defined lambda
Consumer<String> lambda = (s) -> { System.out.println(s); };
String classname = lambda.getClass().getName();
call(classname, "Hello world");
}
}
}
class Host {
public static void action(String aMessage) {
System.out.println(aMessage);
}
}
However, with this code (in both variants, using the static method reference and using the locally declared lambda), I get an exception:
Exception in thread "main" java.lang.ClassNotFoundException: mypackage.SimpleLambda$$Lambda$1/471910020
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at mypackage.SimpleLambda.main(SimpleLambda.java:12)
I would have expected that at I can at least re-instantiate the static method reference... nope, apparently not.
I have been using a similar approach with Groovy Closures and that worked nicely. So am I just doing something wrong with the Java 8 lambdas, or is it not possible to instantiate lambdas by name? I found some hints on the net that lambdas can be (de)serialized, so I would expect it should also be possible to instantiate them by name.
Well, it is a special property of Oracle’s JRE/OpenJDK to use “anonymous classes”, which can’t be accessed by name at all. But even without this, there is no reason why this ought to work:
Class.forName(String) tries to resolve the class via the caller’s ClassLoader. So even if lambda expressions were implemented using ordinary classes, there were not accessible if loaded via a different ClassLoader
Class.newInstance() only works if there is a public no-arg constructor. You can’t assume that there is a no-arg constructor nor that it is public
The assumption that the entire function’s logic has to reside in a single class is wrong. A counter-example would be java.lang.reflect.Proxy which generates interface implementations delegating to an InvocationHandler. Trying to re-instantiate such a proxy via its class name would fail, because you need the to pass the actual InvocationHandler instance to the proxy’s constructor. In principle, the JRE specific lambda expression implementation could use a similar pattern
Considering the points above, it should be clear that you can’t say that it worked with inner classes in general. There are a lot of constraints you have to fulfill for that.
Regarding Serialization, it works for serializable lambda expressions, because the persistent form is completely detached from the runtime implementation class, as described in this answer. So the name of the generated class is not contained in the serialized form and the deserializing end could have an entirely different runtime implementation.
Store the lambda instances in Map, keyed on the instance name. You can make the map globally available trough a singleton wrapper class (just watch out for synchronization issues).
class LambdaMap {
private HashMap<String, Consumer<String>> theMap;
private LambdaMap() {
theMap = new HashMap<>();
}
private static class INSTANCE_HOLDER {
private static LambdaMap INSTANCE = new LambdaMap();
}
public static LambdaMap getInstance() {
return INSTANCE_HOLDER.INSTANCE;
}
public Consumer<String> put(String key, Consumer<String> value) {
return theMap.put(key, value);
}
public static void Call(String aLambdaClassName, String aArg) {
Consumer<String> func = getInstance().theMap.get(aLambdaClassName);
if (func != null) {
func.accept(aArg);
}
}
}
class Host {
public static void action(String aMessage) {
System.out.println("Goodbye, " + aMessage);
}
}
public class GlobalLambdas {
public static void main(String[] args) {
LambdaMap.getInstance().put("print greeting", s -> {
System.out.println("Hello, " + s);
});
LambdaMap.getInstance().put("print goodbye", Host::action);
LambdaMap.Call("print greeting", "John");
LambdaMap.Call("print goodbye", "John");
}
}
run:
Hello, John
Goodbye, John

Expression that behaves differently inside a static method

I'm trying to write an expression or series of statements of Java source code that when written inside a static method evaluates to null, but if the method is non-static evaluates to this.
My initial idea was to 'overload' on static vs non-static, as below:
public class test {
public void method1() {
System.out.println(getThisOrNull());
}
public static void method2() {
System.out.println(getThisOrNull());
}
private static Object getThisOrNull() {
return null;
}
private Object getThisOrNull() {
return this;
}
public static void main(String[] args) {
test t = new test();
System.out.println(t);
t.method1();
t.method2();
}
}
Unfortunately this isn't actually legal Java, you can't 'overload' like that and it just gives a compiler error:
test.java:14: error: method getThisOrNull() is already defined in class test
private Object getThisOrNull() {
^
1 error
Clearly in an ideal world I wouldn't write it like that to begin with, but the problem is this code will be generated automatically by a tool that is not really semantically or syntactically enough to distinguish between the static vs non-static case.
So, how can I write some source code that, although byte for byte identical compiles and behaves differently in depending on the presence of the static modifier for the method?
This can be achieved with a trick and a bit of help from Java's reflection facilities. It's ugly, but it works:
import java.lang.reflect.Field;
public class test {
public void method1() {
System.out.println(getThisOrNull(new Object(){}));
}
public static void method2() {
System.out.println(getThisOrNull(new Object(){}));
}
private static Object getThisOrNull(final Object o) {
for (Field f: o.getClass().getDeclaredFields()) {
if (f.getType().equals(test.class)) {
try {
return f.get(o);
}
catch (IllegalAccessException e) {
// Omm nom nom...
}
}
}
return null;
}
public static void main(String[] args) {
test t = new test();
System.out.println(t);
t.method1();
t.method2();
}
}
This compiles and runs as hoped for:
test#183f74d
test#183f74d
null
The trick that makes this possible is the use of new Object(){}, which creates a new, anonymous class within the existing method that we're trying to figure out if it's static or not. The behaviour of this is subtly different between the two cases.
If the goal were just to figure out if the method is static or not we could write:
java.lang.reflect.Modifiers.isStatic(new Object(){}.getClass().getEnclosingMethod().getModifiers())
Since we want to get this (when available) we need to do something slightly different. Fortunately for us classes defined within the context of an instance of an object in Java get an implicit reference to the class that contains them. (Normally you'd access it with test.this syntax). We needed a way to access test.this if it existed, except we can't actually write test.this anywhere because it too would be syntactically invalid in the static case. It does however exist within the object, as a private member variable. This means that we can find it with reflection, which is what the getThisOrNull static method does with the local anonymous type.
The downside is that we create an anonymous class in every method we use this trick and it probably adds overheads, but if you're backed into a corner and looking for a way of doing this it does at least work.

Overriding default accessor method across different classloaders breaks polymorphism

I come across to a strange behavior while trying to override a method with default accessor (ex: void run()).
According to Java spec, a class can use or override default members of base class if classes belongs to the same package.
Everything works correctly while all classes loaded from the same classloader.
But if I try to load a subclass from separate classloader then polymorphism don't work.
Here is sample:
App.java:
import java.net.*;
import java.lang.reflect.Method;
public class App {
public static class Base {
void run() {
System.out.println("error");
}
}
public static class Inside extends Base {
#Override
void run() {
System.out.println("ok. inside");
}
}
public static void main(String[] args) throws Exception {
{
Base p = (Base) Class.forName(Inside.class.getName()).newInstance();
System.out.println(p.getClass());
p.run();
} {
// path to Outside.class
URL[] url = { new URL("file:/home/mart/workspace6/test2/bin/") };
URLClassLoader ucl = URLClassLoader.newInstance(url);
final Base p = (Base) ucl.loadClass("Outside").newInstance();
System.out.println(p.getClass());
p.run();
// try reflection
Method m = p.getClass().getDeclaredMethod("run");
m.setAccessible(true);
m.invoke(p);
}
}
}
Outside.java: should be in separate folder. otherwise classloader will be the same
public class Outside extends App.Base {
#Override
void run() {
System.out.println("ok. outside");
}
}
The output:
class App$Inside
ok. inside
class Outside
error
ok. outside
So then I call Outside#run() I got Base#run() ("error" in output). Reflections works correctly.
Whats wrong? Or is it expected behavior?
Can I go around this problem somehow?
From Java Virtual Machine Specification:
5.3 Creation and Loading
...
At run time, a class or interface is
determined not by its name alone, but
by a pair: its fully qualified name
and its defining class loader. Each
such class or interface belongs to a
single runtime package. The runtime
package of a class or interface is
determined by the package name and
defining class loader of the class or
interface.
5.4.4 Access Control
...
A field or method R is accessible to a class
or interface D if and only if any of
the following conditions is true:
...
R is either protected or package private (that is, neither public nor
protected nor private), and is
declared by a class in the same
runtime package as D.
The Java Language Specification mandates that a class can only override methods that it can access. If the super class method is not accessible, it is shadowed rather than overridden.
Reflection "works" because you ask Outside.class for its run method. If you ask Base.class instead, you'll get the super implementation:
Method m = Base.class.getDeclaredMethod("run");
m.setAccessible(true);
m.invoke(p);
You can verify that the method is deemed inaccessible by doing:
public class Outside extends Base {
#Override
public void run() {
System.out.println("Outside.");
super.run(); // throws an IllegalAccessError
}
}
So, why is the method not accessible? I am not totally sure, but I suspect that just like equally named classes loaded by different class loaders result in different runtime classes, equally named packages loaded by different class loaders result in different runtime packages.
Edit: Actually, the reflection API says that it's the same package:
Base.class.getPackage() == p.getClass().getPackage() // true
I found the (hack) way to load external class in main classloader so this problem is gone.
Read a class as bytes and invoke protected ClassLoader#defineClass method.
code:
URL[] url = { new URL("file:/home/mart/workspace6/test2/bin/") };
URLClassLoader ucl = URLClassLoader.newInstance(url);
InputStream is = ucl.getResourceAsStream("Outside.class");
byte[] bytes = new byte[is.available()];
is.read(bytes);
Method m = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class });
m.setAccessible(true);
Class<Base> outsideClass = (Class<Base>) m.invoke(Base.class.getClassLoader(), "Outside", bytes, 0, bytes.length);
Base p = outsideClass.newInstance();
System.out.println(p.getClass());
p.run();
outputs ok. outside as expected.

Categories

Resources