Java agent : transform() not invoked for all classes - transform

I have a very simple transformer:
import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
//this class will be registered with instrumentation agent
public class PizzaTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader,
String className,
Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws
IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
System.out.println("This class is "+className);
return byteCode;
}
}
The agent code is as follows:
import java.lang.instrument.Instrumentation;
public class PizzaAgent {
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("Executing premain.........");
inst.addTransformer(new PizzaTransformer(),true);
}
}
The manifest is :
Boot-Class-Path: javassist.jar
Premain-Class: PizzaAgent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
What is puzzling is only 4000+ classes were printed by the transform(), when 19000+ classes are reported as loaded by turning on -verbose:class with command line launching.
Why more than 10000 classes are not invoking transform()?
Thank you

There may be two scenarios,
Class yet not loaded by JVM
If any class yet not loaded by JVM, then there are chances that Java agent : transform() will not be invoked for that classes.
Whenever it will be loaded by JVM Java agent : transform() will be invoked for that class.
Class is loaded before initializing ClassFileTransformer
If you have used any class inside your ClassFileTransformer implementation or any other Agent class, then that class may be loaded before ClassFileTransformer initialization, so Java agent : transform() will not be invoked for that class

You are only seeing classes that are not yet loaded when the agent is attached. If you want to handle loaded classes, too, you have to explicitly retransform these classes. You can do so by:
instrumentation.retransformClasses(instrumentation.getLoadedClasses());
However, some classes are not retransformable (Instrumentation::isModifiable) and you most likely need to split up the array to avoid draining your memory.

Related

IllegalAccessException when accessing ZoneInfo via JSF/EL with JDK 17

While porting a big JEE8 application to Java 17, I stumbled upon an IllegalAccessException when rendering a simple EL expression: #{myWarBean.defaultTZ.rawOffset}. I managed to reproduce the problem in a SSCCE on github. When you run the application on Wildfly application server (I'm using 26.1.1.Final), you get the following stacktrace:
SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (default task-1) Error Rendering View[/index.xhtml]: javax.el.ELException: /index.xhtml #23,74 value="raw offset=#{myWarBean.defaultTZ.rawOffset}": java.lang.IllegalAccessException: class javax.el.BeanELResolver cannot access class sun.util.calendar.ZoneInfo (in module java.base) because module java.base does not export sun.util.calendar to unnamed module #6a1cb0de
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:77)
at javax.faces.api#3.1.0.SP01//javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
at javax.faces.api#3.1.0.SP01//javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:181)
at javax.faces.api#3.1.0.SP01//javax.faces.component.UIOutput.getValue(UIOutput.java:140)
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:198)
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:328)
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:143)
at javax.faces.api#3.1.0.SP01//javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:600)
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:286)
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:90)
at javax.faces.api#3.1.0.SP01//javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:571)
at javax.faces.api#3.1.0.SP01//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1648)
at javax.faces.api#3.1.0.SP01//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1651)
at javax.faces.api#3.1.0.SP01//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1651)
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:461)
[...]
Caused by: javax.el.ELException: java.lang.IllegalAccessException: class javax.el.BeanELResolver cannot access class sun.util.calendar.ZoneInfo (in module java.base) because module java.base does not export sun.util.calendar to unnamed module #6a1cb0de
at javax.el.api#2.0.0.Final//javax.el.BeanELResolver.getValue(BeanELResolver.java:193)
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:156)
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:184)
at org.glassfish.jakarta.el#3.0.3.jbossorg-4//com.sun.el.parser.AstValue.getValue(AstValue.java:114)
at org.glassfish.jakarta.el#3.0.3.jbossorg-4//com.sun.el.parser.AstValue.getValue(AstValue.java:177)
at org.glassfish.jakarta.el#3.0.3.jbossorg-4//com.sun.el.parser.AstDeferredExpression.getValue(AstDeferredExpression.java:39)
at org.glassfish.jakarta.el#3.0.3.jbossorg-4//com.sun.el.parser.AstCompositeExpression.getValue(AstCompositeExpression.java:44)
at org.glassfish.jakarta.el#3.0.3.jbossorg-4//com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:183)
at org.jboss.weld.core#3.1.9.Final//org.jboss.weld.module.web.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at org.jboss.weld.core#3.1.9.Final//org.jboss.weld.module.web.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at com.sun.jsf-impl#2.3.17.SP01//com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:73)
... 73 more
Caused by: java.lang.IllegalAccessException: class javax.el.BeanELResolver cannot access class sun.util.calendar.ZoneInfo (in module java.base) because module java.base does not export sun.util.calendar to unnamed module #6a1cb0de
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:392)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:674)
at java.base/java.lang.reflect.Method.invoke(Method.java:560)
at javax.el.api#2.0.0.Final//javax.el.BeanELResolver.getValue(BeanELResolver.java:186)
... 83 more
It seems, the problem is the EL expression accessing a java.util.TimeZone. The TimeZone class uses sun.util.calendar.ZoneInfo internally. And it seems this is not legal any more.
This only happens with Java 17. When running in Java 11, this all works fine.
I can workaround the exception by adding the following arguments when starting wildfly:
--add-exports=java.base/sun.util.calendar=ALL-UNNAMED
However, I think it should be possible to run the example without this workaround.
Any ideas what I'm missing? Might this even be a bug in Java/JDK 17?
It's reproducible with a plain Java application class as follows:
package com.stackoverflow.q72361100;
import java.lang.reflect.Method;
import java.util.TimeZone;
public class Test {
public static void main(String... args) throws Exception {
TimeZone instance = TimeZone.getDefault();
Class<?> cls = instance.getClass();
Method method = cls.getMethod("getRawOffset");
Object result = method.invoke(instance); // java.lang.IllegalAccessException
System.out.println(result);
}
}
The issue here is that instance.getClass() returns sun.util.calendar.ZoneInfo as that's the implementation returned by TimeZone#getDefault(). The work around would be to use TimeZone.class instead of instance.getClass():
package com.stackoverflow.q72361100;
import java.lang.reflect.Method;
import java.util.TimeZone;
public class Test {
public static void main(String... args) throws Exception {
TimeZone instance = TimeZone.getDefault();
Class<?> cls = TimeZone.class; // Work around
Method method = cls.getMethod("getRawOffset");
Object result = method.invoke(instance);
System.out.println(result);
}
}
I'd argue that this will require a change in EL spec. Ideally it should search further in declared super classes if the method is accessible as per Method#canAccess() and then use it instead.
package com.stackoverflow.q72361100;
import java.lang.reflect.Method;
import java.util.TimeZone;
public class Test {
public static void main(String... args) throws Exception {
TimeZone instance = TimeZone.getDefault();
Class<?> cls = instance.getClass();
Method method = getAccessibleMethod(instance, cls, "getRawOffset"); // Look in superclasses as well.
Object result = method.invoke(instance);
System.out.println(result);
}
private static Method getAccessibleMethod(Object instance, Class<?> cls, String methodName) throws NoSuchMethodException {
Method method = cls.getMethod(methodName);
if (method.canAccess(instance)) {
return method;
}
return getAccessibleMethod(instance, cls.getSuperclass(), methodName);
}
}
I've created an issue at EL spec: https://github.com/jakartaee/expression-language/issues/188
Until they get it fixed, you can work around it by adding a dedicated getter for it:
public int getDefaultTZrawOffset() {
return getDefaultTZ().getRawOffset();
}
#{myWarBean.defaultTZrawOffset}

Changing class loader for flow assembly

I am using Spring Web flow 2.4.8.RELEASE with Spring version 4.3.11. There are certain classes being used in the flow file that are not part of standard class loader. They are being loaded using application specific class loader.
How can I change change the class loader used by FlowModelFlowBuilder?
java.lang.IllegalArgumentException: Unable to load class '<CLASS TO LOAD USING DIFFERENT CLASS LOADER>'
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.toClass(FlowModelFlowBuilder.java:977)
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseFlowVariable(FlowModelFlowBuilder.java:402)
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.buildVariables(FlowModelFlowBuilder.java:181)
at org.springframework.webflow.engine.builder.FlowAssembler.directAssembly(FlowAssembler.java:103)
at org.springframework.webflow.engine.builder.FlowAssembler.assembleFlow(FlowAssembler.java:91)
at org.springframework.webflow.engine.builder.DefaultFlowHolder.assembleFlow(DefaultFlowHolder.java:109)
at org.springframework.webflow.engine.builder.DefaultFlowHolder.getFlowDefinition(DefaultFlowHolder.java:84)
at org.springframework.webflow.definition.registry.FlowDefinitionRegistryImpl.getFlowDefinition(FlowDefinitionRegistryImpl.java:60)
at org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:138)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:263)
at org.springframework.faces.webflow.JsfFlowHandlerAdapter.handle(JsfFlowHandlerAdapter.java:57)
FlowModelFlowBuilder calls getLocalContext().getApplicationContext().getClassLoader() to get the class loader. It return instance of ParallelWebappClassLoader.
I am looking for a way to let FlowModelFlowBuilder to specify custom class loader. Is it possible to customize FlowModelFlowBuilder?
Found another way. Instead of trying to find way to customize the Flow specifics, used ContextRefreshedEvent Listener and changed the class loader. As the beans are loaded after the context refreshed, following approach worked
public class WebflowApplicationContextListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent( final ContextRefreshedEvent p_event ) {
ApplicationContext l_appContext = p_event.getApplicationContext();
if ( l_appContext instanceof GenericWebApplicationContext ) {
( (GenericWebApplicationContext) l_appContext ).setClassLoader( getSpecificContextClassLoader() );
}
}
}

Import inner enum in Groovy script

I have a Groovy class defined in Vehicles.groovy that contains some inner enums:
public class Vehicles {
public enum Land {
BICYCLE,
CAR,
TRAIN
}
public enum Water {
SAILBOAT,
MOTORBOAT
}
public enum Air {
JET,
HELICOPTER
}
}
I'd like to reference these enums in a script run.groovy in the same directory as Vehicles.groovy.
Fully qualifying the enum instance works.
import Vehicles
println Vehicles.Land.BICYCLE
or
import static Vehicles.Land
println Vehicles.Land.BICYCLE
or
import Vehicles.Land.*
println Vehicles.Land.BICYCLE
correctly print BICYCLE.
However, I'd like to reference the Land enum without fully qualifying it.
I basically tried every combination of static/non-static, aliased/non-aliased, and star/non-star imports.
import Vehicles.Land or import static Vehicles.Land.* (or import Vehicles.Land as Land) give unable to resolve class errors. This seems weird because they're what one would do in Java (correct me if I'm wrong.)
If I try
import static Vehicles.Land
println Land.BICYCLE
or
import static Vehicles.Land as Land
println Land.BICYCLE
or
import Vehicles.Land.*
println Land.BICYCLE
, I get the error
Caught: groovy.lang.MissingPropertyException: No such property: Land for class: run
groovy.lang.MissingPropertyException: No such property: Land for class: run
at run.run(run.groovy:2)
Similarly,
import Vehicles.Land.*
println BICYCLE
gives
Caught: groovy.lang.MissingPropertyException: No such property: BICYCLE for class: run
groovy.lang.MissingPropertyException: No such property: BICYCLE for class: run
at run.run(run.groovy:2)
Adding package declarations to both Vehicles.groovy and run.groovy doesn't seem to help, either.
So...
What support does Groovy have for importing inner classes? Why is it it different from Java?
How can I get Groovy to allow me to reference non-fully-qualified inner enums?
Note: I'm using Groovy 1.8.6 and Oracle JDK 1.8.0_45.
Groovy does support import nested classes, including enums. However to access them without full qualification, you'll need to import them in a non-static manner (unlike Java), or explicitly declare them static:
// Explicitly declare Water and Air as static to demonstrate
public class Vehicles {
public enum Land { BICYCLE, CAR, TRAIN }
public static enum Water { SAILBOAT, MOTORBOAT }
public static enum Air { JET, HELICOPTER }
}
// Non-static nested enum needs non-static import (unlike Java)
import Vehicles.Land
println Land.BICYCLE
// Explicitly static nested enum can be static imported
import static Vehicles.Water
println Water.SAILBOAT
// Explicitly static nested enum can also be non-static imported as well!
import Vehicles.Air
println Air.JET
Working example: https://groovyconsole.appspot.com/script/5089946750681088
Unlike Java where enums are implicitly static, it appears that enums in Groovy are not implicitly static, hence why static imports don't work. This is because enums in Groovy aren't actually the same as the ones in Java, they made enhancements. Unfortunately it seems they have forgotten to tell the compiler to also make them implicitly static (at least as of 2.4.4).
My suggestion is to explicitly declare them static (if you can) as it would be keeping with the Groovy notion that valid Java is valid Groovy.
Have you tried below?
import static Vehicles.Land.*
println BICYCLE
EDIT: is this what you are looking for?

How DbContext initializes automatic DbSet<T> properties?

Consider the following class:
class MyContext : DbContext
{
public DbSet<Order> Orders { get; set; }
}
and instantiating a new object:
var mycontext = new MyContext();
Why mycontext.Orders is not null? When it was initialized? Who has initialized it? I'm really confused because the base class (DbConetxt) cannot access the derived class properties so it is not possible that the automatic property was initialized in the base object.
From looking at the reflected code, when the DbContext (the base class) is constructed it makes a call to the DbSetDiscoveryService (an internal clasS) - which essentially uses reflection to find all properties on the DbContext, and then initializes those that need initializing.
So in short - using reflection in the constructor.

JUnit #Before method ordering in Groovy

I am used to JUnit running #Before methods in a superclass before #Before methods in a subclass. However, I've got a Groovy test class which inherits from another Groovy class, and they both contain #Before methods; the problem I have is that #Before method in the test class is running before the one in its superclass, and I'm getting NPEs from uninitialised variables (the superclass is supposed to take care of that).
The superclass is something like this:
import groovyx.net.http.RESTClient
import org.junit.Before
abstract class BaseTestClass {
def client
#Before
void setUp() {
client = new RESTClient()
}
}
And the subclass is something like this:
import org.junit.Before
class TestClass extends BaseTestClass {
#Before
void setUp() {
client.post(path: '/entity', body: '{"id":"test"}')
}
...
}
This is a simplified version, but I get the error: java.lang.NullPointerException: Cannot invoke method post() on null object in the setUp() method of the subclass. Any ideas what could cause this behaviour? All the docs say it should be the other way round, and I've never previously experienced any different.
I'm running using the maven-failsafe-plugin, junit-4.10 and jdk-1.6.0_31. Interestingly, I have other Groovy test classes in the same place (same package, same project, same directory) which do not suffer from this problem - the ordering of #Before methods is correct; furthermore, it appears to be deterministic - it's always the same test class that has the problem.
Thanks!
You named both of your #Before methods setUp(). The child's setUp() method overrides the parent's one. So the line client = new RESTClient() is never called.
Just pick another name.

Resources