package vs. protected protection with Java reflection - java

Why can I use reflection to instantiate a inner protected class, but not an inner class with package-level protection? I wouldn't think either would be accessible outside the package.
Consider the following example:
package dummy;
public class ClassContainer {
protected static class InnerProtected {
public InnerProtected() {}
}
static class InnerDefault {
public InnerDefault() {}
}
private class InnerPrivate {
public InnerPrivate() {}
}
}
package driver;
public class DriverClass {
public static void main(String[] args) throws Exception {
Class.forName("dummy.ClassContainer$InnerProtected").newInstance();
Class.forName("dummy.ClassContainer$InnerDefault").newInstance();
Class.forName("dummy.ClassContainer$InnerPrivate").newInstance();
}
}
Notice that the two classes are in different packages.
The first line in main (which instantiates InnerProtected) works.
The second line (which instantiates InnerDefault) throws this exception:
Exception in thread "main" java.lang.IllegalAccessException: Class driver.DriverClass can not access a member of class dummy.ClassContainer$InnerDefault with modifiers "public"
Since the driver is an a different package than the class definitions, shouldn't both attempts at instantiating the classes fail?
(For what it's worth: Attempting to instantiate InnerPrivate fails as I would expect:
Exception in thread "main" java.lang.InstantiationException: dummy.ClassContainer$InnerPrivate

Really, javap reports that InnerProtected is compiled as public, whereas other member classes are package-private.
I believe it's caused by the need to make it visible to subclasses of ClassContainer from different packages. Perhaps VM cannot handle access control rules in this case, so that they are handled at compiler level.
Note, however, that if you omit constuctor declarations for these classes their generated constructors would have their expected visililities, that is protected, default and private respectively.

Related

ByteBuddy - Read class annotations in a java agent

I am trying to access annotations of a class before applying some transformation in a java agent implemented with ByteBuddy.
To access the annotations, I am trying to load the Class object, but it seems that this creates a duplicate class definition.
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
public class SimpleTestAgent {
public static void premain(String arg, Instrumentation inst) {
new AgentBuilder.Default()
.type(ElementMatchers.isAnnotatedWith(SomeAnnotationType.class))
.transform((builder, type, classLoader, javaModule) -> {
try {
Class loadedClass = Class.forName(type.getName(), true, classLoader);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return builder;
})
.installOn(inst);
}
}
A simple class that just creates an instance of the class TestClass that is annotated with the expected annotation, throws the following exception:
Exception in thread "main" java.lang.LinkageError: loader (instance of
sun/misc/Launcher$AppClassLoader): attempted duplicate class
definition for name: "TestClass"
public class AgentTest {
public static void main (String[] args) {
TestClass pet = new TestClass();
}
}
I am trying to implement the agent like in the example described in: Easily-Create-Java-Agents-with-ByteBuddy
Is there a way to load the Class object without causing this issue or a way to access the annotations using the arguments passed to the transformation() method?
The transformation should be able to implement new interfaces and not only override methods this is why I think I cannot use "ForAdvice".
UPDATE
The following loop finds the TestClass only after the Class.forName() is executed. This means that the class has not been loaded and so probably there is no hope to use Class.forName to get the annotations.
for (Class<?> t : inst.getAllLoadedClasses()) {
System.out.println("Class name: " + t.getName());
}
It is possible to get the annotations and the full information about a class using the net.bytebuddy.description.type.TypeDescription instance passed to the transform() method.
The problem is that, for example, I need the Method objects that can be called using reflection. It would be easier if I could somehow access the Class object for the class that is being transformed.
Byte Buddy exposes all information on annotations of a class via the TypeDescription API already, you should not load classes as a class that is loaded during a transformation loads this class before the transformation is applied and aborts class loading with the error you observe. Instead, implement your own matcher:
.type(type -> check(type.getDeclaredAnnotations().ofType(SomeAnnotation.class).load())
Byte Buddy will represent the annotation for you without loading the carrier class itself but rather represent it using its own class file processor.
You should make sure the annotation class is loaded before installing your agent builder to avoid a circularity for this exact annotation.

Spring Boot - Could not find a suitable constructor error

Hi I am trying to read a file as an argument from the main class and accessing the argument in another class in Spring boot.
The main class looks like this
public class DemorestApplication extends SpringBootServletInitializer {
public static void main(String[] args) throws IOException {
new DemorestApplication().configure(new SpringApplicationBuilder(DemorestApplication.class)).run(args);
new UsersResources(args[0]);
}
}
And I am passing an argument to another class named UsersResources constructor
#Path("/sample")
public class UsersResources {
private String value;
UsersResources(String value){
this.value=value;
}
//new code
#GET
#Path("Data/file/{path}")
#Produces("application/json")
public Map<String, Map<String, List<Map<String, Map<String, String>>>>> getApplicationName1(#PathParam("path") String path) throws IOException {
ReadExceldy prop = new ReadExceldy();
FileInputStream Fs = new FileInputStream(System.getProperty("user.dir")+"\\"+value);
Properties properties = new Properties();
properties.load(Fs);
String Loc=properties.getProperty("filepath");
String Na=path;
String filename=Loc+Na;
return prop.fileToJson(filename);
}
}
I'm trying to run this code but it's throwing an error saying
java.lang.NoSuchMethodException: Could not find a suitable constructor in com.springsampleapplication.UsersResources class
at org.glassfish.jersey.internal.inject.JerseyClassAnalyzer.getConstructor(JerseyClassAnalyzer.java:192) ~[jersey-common-2.25.1.jar:na]
The issue might be with Spring trying to initialize UsersResources class and expecting a constructor with no arguments, when you have it only with a String parameter. Try adding such constructor: public UsersResources() {}
Other thought that came into mind is that this could be because of UsersResources constructor not having a visibility modifier (it means it is package protected), you could try adding public visibility modifier to it (though Spring should be able to initialize even private constructors). Are the DemorestApplication and UsersResources classes in the same package though? As otherwise the code should not compile, since UsersResources(String value) is not visible outside of the package it is in. But the error is a bit different in such case: The constructor xxx is undefined, so probably this is not the case.
Since it seems you are using Jersey you need to have a public constructor:
Root resource classes are instantiated by the JAX-RS runtime and MUST have a public constructor for which the JAX-RS runtime can provide all parameter values. Note that a zero argument constructor is permissible under this rule.
See How to register a static class in Jersey?
Since you have defined a constructor in your class, no default constructor is generated. A work around is to make this class a Spring component with #Component et al.

Assign weaker access to method overriding from superclass

I have a Class called Module which has a Method onEnable();
Now i have a class called Config and want to make the onEnable(); method private because there is a predefined acting and a class extending Config should'nt be allowed to change the behaviour.
Is there any way to do this?
Example
class Module{
public void onEnable(){
}
}
A class extending Module which is allowed to use onEnable:
class HelloWorldModule{
#Override
public void onEnable(){
System.out.println("Hello, World!");
}
}
Now the config Class, where i want that onEnable is private so that Classes which extend Config cannot! Override onEnable:
class Config{
#Override
private void onEnable(){
}
}
So NOW, a class named ProgrammConfig which extends Config cannot override onEnable.
However, this is not working because you cannot override a public method to a private method.
By declaring a method as public, you are saying that it should be possible to call said method on every instance of this class, including subclasses. Declaring a method as private in a subclass doesn't make sense, and is thus not allowed.
Now, if you're concerned about subclasses overriding the method, you can declare the method as final to prevent this:
class Config extends Module{
#Override
public final void onEnable(){}
//Whatever
}
You cannot solve this using inheritance. If Config is a subclass of Module, then it must provide all functions of Module with (at most) the same access restrictions. Think of a subclass as a specialized version of the superclass: It can do everything the superclass can, likely more, but never less.
Still you can implement a Config class as desired. Just skip subclassing, and instead use a private field of type Module like so:
class Config {
private Module module;
public Config() {
module = new Module();
}
public int SomeFunctionFromModuleYouWantToExpose() {
return module.SomeFunctionFromModuleYouWantToExpose();
}
// ...
}

Interception on constructor causes ClassNotFoundException

I'm trying to intercept constructors annotated with #Inject. That worked fine in the context of a small unit test. However in the context of a DI container like Spring it fails with a ClassNotFoundException.
I managed to narrow down on the root cause. Calling getDeclaredConstructors on the instrumented class will trigger this exception. Interestingly enough, if we first create an instance of that class, the problem disappears.
For example:
public class InterceptConstructorTest {
#Test
public void testConstructorInterception() throws ClassNotFoundException {
ByteBuddyAgent.install();
new AgentBuilder.Default().type(nameStartsWith("test")).transform(new AgentBuilder.Transformer() {
#Override
public Builder<?> transform(Builder<?> builder, TypeDescription td) {
return builder.constructor(isAnnotatedWith(Inject.class))
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.to(ConstructorInterceptor.class)));
}
}).installOnByteBuddyAgent();
// If this line is uncommented, ClassNotFoundException won't be thrown
// MyClass myClass = new MyClass("a param");
// Manually load MyClass
Class<?> myClassDefinition = getClass().getClassLoader().loadClass("test.MyClass");
// Throws NoClassDefFoundError
for(Constructor<?> constructor : myClassDefinition.getDeclaredConstructors()) {
System.out.println(constructor);
}
}
}
The stack stack trace can be found: http://pastebin.com/1zhx3fVX
class MyClass {
#Inject
public MyClass(String aParam) {
System.out.println("constructor called");
}
}
class ConstructorInterceptor {
public static void intercept() {
System.out.println("Intercepted");
}
}
The problem in this case is the constructor injection. In order to rebase a constructor, Byte Buddy needs to create an additional type and creates a class like the following:
class MyClass {
private synthetic MyClass(String aParam, $SomeType ignored) {
System.out.println("constructor called");
}
#Inject
public MyClass(String aParam) {
this(aParam, null);
// Instrumentation logic.
}
}
The additional type is unfortunately necessary to create a unique signature for the rebased constructors. With methods, Byte Buddy can rather change the name but for constructors that is not possible as they must be named <init> in the class file to be recognized as constructors.
Byte Buddy tries to only load auxiliary classes after a type was instrumented. Depending on the virtual machine, loading a class that references another class causes the loading of the referenced type. If this type is the instrumented class, the instrumentation aborts the ongoing instrumentation for the circularity.
Therefore, Byte Buddy makes sure that any auxiliary type is only loaded at the first possible point after it can be sure that the instrumented type is loaded. And it does this by adding a self-initialization into the instrumented class's class initializer. In a way, Byte Buddy adds a block:
static {
ByteBuddy.loadAuxiliaryTypes(MyClass.class);
}
If this block is not executed before reflecting on the class, the auxiliary type is not loaded and the exception you encounter is thrown. If you called:
Class.forName("test.MyClass", true, getClass().getClassLoader());
instead of loadClass, the problem would not occur where the second parameter indicates to execute the class initializer eagerly. Also, the initializer is executed if you create an instance.
Of course, this is not satisfactory, I am now adding some logic to decide for an auxiliary type if it can be loaded during the instrumentation to avoid such errors.

Java newbie problem: package with private access

Pack.java imports pack.TestPack; but it cannot access it. I cannot understand why it cannot access the class despite the import.
Error
Pack.java:7: TestPack() is not public in pack.TestPack; cannot be accessed from outside package
System.out.println(new TestPack().getHello());
^
1 error
Pack.java
import pack.TestPack;
import java.io.*;
public class Pack
{
public static void main(String[] args){
System.out.println(new TestPack().getHello());
}
}
TestPack.java
package pack;
import java.util.*;
import java.io.*;
public class TestPack
{
private String hello="if you see me, you ar inside class TestPack";
public String getHello(){return hello;}
TestPack(){}
}
You should make TestPack's constructor public.
public class TestPack
{
private String hello="if you see me, you ar inside class TestPack";
public String getHello(){return hello;}
public TestPack(){}
}
The thing is, even though TestPack visibility is public, its parameterless constructor visibility is package (which is the visibility when you don't specify one explicitly).
package visibility means that classes in the same package will be able to see it. Since TestPack and Pack are not in the same package, Pack can't call TestPack's constructor.
In the way you are using getHello function, you may start thinking using static methods
public class TestPack
{
private static String hello="if you see me, you ar inside class TestPack";
public static String getHello(){return hello;}
private TestPack(){}
}
then you just will do:
public class Pack
{
public static void main(String[] args){
System.out.println(TestPack.getHello());
}
}
I suggest that you don't make the class public but make the constructor public and have folks use a public interface that your class implements. It is a good idea to start the API to your package to be public interfaces (and perhaps some public abstract classes) and hide your implementation classes by not marking them as public so that you can change these over time. You can then provide a public factory methods in your package which instantiate your package private class and return them as the interface types. Here is an interface which is public:
package stackoverflow;
public interface Widget {
public void doWidgetWork(String work);
}
Here is the implementation which is "package private". The compiler wont let code outside of the same package import nor use this class at all:
package stackoverflow;
/*package*/ class WidgetHidden implements Widget {
public WidgetHidden(String configOptionA, String configOptionB){
// ...
}
public WidgetHidden(){
// ...
}
public void doWidgetWork(String work)[
// ...
}
}
notice there that the second occurrence of the word /package/ is a comment (it is not legal in java to use that word there) but many programmers use such a comment in that position to show people that it was not an accident that the class is not public; it signifies that the developer really intended that the class is deliberately "package private". To let people instantiate the class from outside of your package you provide a static factory class (else an instance factory class):
package stackoverflow;
public class WidgetFactory {
public static Widget newInstance( String configOptionA, String configOptionB) {
return new Widget( String configOptionA, String configOptionB);
}
}
The whole point of the factory class is that it hides your internal classes (the ones you hide as package private). Over time you can change your factory classes to return new classes or rename or delete the WidgetHidden class.
Many frameworks indicate which classes other developers should not use by putting them into a package with the name "internal" in it. The public interfaces would be in the main package (e.g. "com.stackoverflow.widget") and the hidden classes into your internal package which only exposes public factory classes (e.g. "com.stackoverflow.widget.internal").
A variation on the theme is to not use a static method on the factory class; make it a regular method. The alternatives are called "static factories" or "instance factories" depending on whether the method is static or not. Not making the method static seems like more work for people using your package as they first have to instantiate your factory object before using it to create Widget. Where is helpful is when people might want to set some defaults for all widgets on the constructor of the factory then use the none static newInstance methods to specify anything beyond the defaults:
public class WidgetInstanceFactory {
private String defaultOptionA = null;
public WidgetInstanceFactory( String defaultOptionA ) {
this.defaultOptionA = defaultOptionA;
}
public Widget newInstance( String optionB ) {
return new WidgetHidden( this.defaultOptionA, optionB );
}
}
It is possible to get around package private protection using reflection to find and invoke the constructor. A really nice feature of the Spring framework it that it will instantiate classes that are not public even when there is no factory class (although it is more polite to provide factory classes which Spring is happy to use also). The following code will work:
package stackoverflow.other;
class TestInstantiate {
private Widget myWidget = null;
public TestInstantiate(){
this.myWidget = instantiatePackagePrivateClass("stackoverflow.WidgetHidden");
}
private Widget instantiatePackagePrivateClass(String className)
throws ClassNotFoundException, NoSuchMethodException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
#SuppressWarnings("unchecked")
Class<FileUploadSequence> clazz = (Class<Widget>) Class.forName(className);
Constructor<Widget> constructor = clazz.getConstructor(new Class[]{});
constructor.setAccessible(true);
Widget widget = (Widget) constructor.newInstance((Object[])null);
return widget;
}
}
In that example I used the no arguments constructor but clearly you can find and invoke the two string constructor using the same approach. Clearly such code gets around the intention of the programmer who wrote WidgetHidden; they wanted to hide it as they are likely to change it. Anyone who uses such a back door to manipulate the package private object should be aware that the class WidgetHidden is not part of the public API of the framework they are using so it likely to be deleted or changed without prior notice by the developer who wrote the package you are using. Renaming it to be WidgetInternal and putting it into an "internal" package make it every more the case you are telling people "do not uses". The JVM has optional security setting which prevent people from doing such tricks; but the person running the JVM has to configure it externally to dis-allow such tricks which is only useful when you want to run someone else code you don't trust and prevent it from pulling such tricks.
The book Effective Java by Josha Block 2nd Edition has a lot of discussion and examples and details of the pitfalls when trying to write a good API. It has a lot of detail to explain why you should always look to hide as many classes as you can with lots of other good "tricks of the trade".

Categories

Resources