Bytebuddy loaded class not found - byte-buddy

I am trying to build a class that holds a reference to another class object through a field. Something like this:
Class A extends Parent {private B b;}
Class B extends Child {private String s;}
I am able to make and load Class B first, instantiate its object and set it to the field in class A by intercepting A's constructor.
However, when I try to load the unloaded type A it throws class not found exception for type B even though its already loaded.
I hope this is possible to do with bytebuddy. If yes, what am I doing wrong?
Here is the implementation:
private static final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader();
public Class<? extends Parent> generateParentClass(ParentConfig config) throws Exception {
Map<String, Class<? extends Child>> fieldMap = config.getChildren().stream().collect(Collectors.toMap(ChildConfig::getName, this::generateChildClass));
Implementation.Composable constructorInterceptor = MethodCall.invoke(Parent.class.getConstructor());
for(Map.Entry<String, Class<? extends Child>> entry : fieldMap.entrySet()) {
Child child = entry.getValue().getDeclaredConstructor().newInstance();
constructorInterceptor = constructorInterceptor.andThen(FieldAccessor.ofField(entry.getKey()).setsReference(child));
}
DynamicType.Builder<Parent> typeBuilder = new ByteBuddy()
.subclass(Parent.class)
.name(Parent.class.getPackageName() + "." + config.getType())
.annotateType(Parent.class.getAnnotations())
.constructor(any())
.intercept(constructorInterceptor);
for(Map.Entry<String, Class<? extends Child>> entry : fieldMap.entrySet())
typeBuilder = typeBuilder.defineField(entry.getKey(), entry.getValue(), Modifier.PRIVATE);
DynamicType.Unloaded<Parent> unloadedType = typeBuilder.make();
return unloadedType.load(SYSTEM_CLASS_LOADER).getLoaded(); //ClassNotFoundException for Type Child
}
private Class<? extends Child> generateChildClass(ChildConfig config) {
DynamicType.Builder<Child> typeBuilder = new ByteBuddy()
.subclass(Child.class)
.name(Child.class.getPackageName() + "." + config.getName())
.annotateType(Child.class.getAnnotations());
for(Attribute attribute : config.getAttributes())
typeBuilder = typeBuilder.defineField(attribute.getName(), attribute.getTypeClass(), Modifier.PRIVATE);
DynamicType.Unloaded<Child> unloadedType = typeBuilder.make();
return unloadedType.load(SYSTEM_CLASS_LOADER).getLoaded();
}

Whenever you run unloadedType.load(SYSTEM_CLASS_LOADER), you create a new class loader. All types that are loaded within this class loader are not visible to other classes outside of it. What you can do is to merge two unloadedType values and load them together into the same class loader. Types are still available via TypeDescriptions. Alternatively, you can define a custom ClassLoadingStrategy or use a default strategy that uses injection via unsafe or via a method handle lookup (Java 9+). The load method accepts it as its second argument.

Related

Static and Non Static in TestNg

I have senario where I want to understand use access modifier Static and non static in TestNG. Here is actual code `
public class BaseClass {
public WebDriver driver =null;
public File f = null;
public FileInputStream fs = null;
public static Properties config = null;
private final String configPath="C:\\Users\\prakumak\\eclipse-workspace\\WebDriverTestNGDDFramwork\\src\\MangoHCM\\Config.properties";
#BeforeClass
public void setup() throws Exception {
f = new File(configPath);
try {
fs = new FileInputStream(f);
config = new Properties();
config.load(fs);
}catch(FileNotFoundException e) {
System.out.println(" File is not present");
}catch(IOException e) {
System.out.println("File not loaded");
}
if(config.getProperty("BrowserName").equalsIgnoreCase("Firefox")) {
driver = new FirefoxDriver();
}else if(config.getProperty("BrowserName").equalsIgnoreCase("Chrome")) {
driver = new ChromeDriver();
}else {
throw new Exception("BrowserName is either not mentione OR not correct");
}
}
Scenario 1: When I make Properties variable STATIC and setup() method as NON static, I am still able to call Properties variable in non-static setup() method directly. How could it possible to use static variable in non static method ?
scenario 2: When I make Setup() method as STATIC and Properties variable as non-static then I am getting error saying that "annot make a static reference to the non-static field ". This is OK for me.
Please help me to static how does static and non static work in TestNG? Is it same as normal concept of Java or something is different here? does adding annotation in any menthod in testNG makes it static?
The concept of static and non-static are the same in Java and TestNG.
Non-static always requires a context, referenced by this. Static does not require a context, but you can use the class name. Use of the class name is not required if your code is within that class (i.e. BaseClass.config). The same rule applies for methods (i.e. BaseClass.setup() in your code, unless setup is declared as static).
If you add a non-static setup() method annotated with #Before, you would have two methods, one that requires a context and one that does not. To make your code more readable, i suggest that you rename your static setup() method to setupClass().
Since your method is annotated with #BeforeClass, it has to be static. It is bound to the class and not to a context. This is implicitly required by #BeforeClass.
#BeforeClass requires a static method
#Before requires a non-static method
You can always access field and methods that do not require a context from methods that do require a context. Keep in mind that fields that have no context are shared by static and non-static methods and even between different non-static methods that have a different context.
Basic rule is to stick with the same modifier, either non-static or static, for fields and methods.

How do I load a component inside a class that extends BaseAuthenticate in CakePHP?

I have created my own authenticator which handles OAuth 2:
class OauthAuthenticate extends BaseAuthenticate
I would like to use a custom component (extended from Component) in my OauthAuthenticate class.
How can I to load my component there? The traditional
public $components = array('OauthAuthenticate');
doesn't work - the component is not loaded.
BaseAuthenticate class cannot load component via $components array as is usual in controllers, but loading a component is possible in constructor:
private $utilComponent = null;
public function __construct(ComponentCollection $collection, array $settings)
{
$this->utilComponent = $collection->load('Util');
}

CDI injection not done in base class for jax-rs controller

I'm struggling with CDI and class inheritence.
I've a JAX-RS controller declared as :
#Path("/share")
public class ControllerShare extends BaseController {
#Inject
private ServiceShare serviceShare;
#PostConstruct
private void verifInit() throws ExceptionTechnique {
log.warn("Checking CDI injection");
if (serviceShare == null) {
log.error("serviceAccount not initialized. Check your EJB configuration");
throw new ExceptionTechnique("serviceShare not initialized. Check your EJB configuration.");
}
}
...
}
This controller extends a base controller declared as :
public abstract class BaseController {
private Logger log = LoggerFactory.getLogger(ControllerShare.class);
#Context protected HttpServletRequest request;
#Inject private ControlerSession ctrlSession;
public BaseController() {}
#PostConstruct
private void verifInit() throws ExceptionTechnique {
log.warn("Checking CDI injection");
if (ctrlSession == null) {
log.error("controllerSession not initialized. Check your CDI configuration");
throw new ExceptionTechnique("serviceAccount not initialized. Check your CDI configuration.");
}
}
...
}
The problem is that injection is correctly done in ControllerShare (I correctly see "Checking CDI injection"), but is not done in the BaseController class (ctrlSession is null).
I try #Named and others combination without success. Injection is just done in ControllerShare and not in BaseController.
EDIT:
One more thing : curiously the #Context is working fine. My request is set and the value is correct.
Thank's for any explanation and solution.
Actually, this should work according to
http://docs.jboss.org/cdi/spec/1.0/html/inheritance.html
4.2. Inheritance of member-level metadata
Suppose a class X is extended directly or indirectly by the bean class of a managed bean or session bean Y.
If X declares an injected field x then Y inherits x.
On a side note: #PostConstruct however is not inherited if you specify it anew. Therefore, in your sub-class your method must be named differently to have both initializers executed.
If X declares an initializer, non-static observer, #PostConstruct or #PreDestroy method x() then Y inherits x() if and only if neither Y nor any intermediate class that is a subclass of X and a superclass of Y overrides the method x().

Serialize class based on one interface it implements with Jackson or Gson

I have the following:
An interface I1 extends Ia, Ib, Ic
An interface I2.
A class C implements I1, I2. And this class has its own setters and getters as well.
C cInstance = new C():
//Jackson
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(new File("somefile.json"), cInstance);
//Gson
Gson gson = new Gson();
String json = gson.toJson(cInstance);
The output will be cInstance serialized according to the properties of C and what it inherited.
However, I like the properties are being serialized to be according to the setters/getters in I1 (only the cInstance properties represented in the I1 interface).
How can I do this with Jackson knowing that I have too many classes with the same problem and I can't modify the class definition or add annotations.
And the same issue applies to Deserialization (Deserializing according to an interface)
Thanks
First of all, you can always attach "mix-in annotations" even without adding annotations directly (see wiki page). With this, annotation to use would be:
#JsonSerialize(as=MyInterface.class)
but if you do not want to use mix-ins, you can force specific type to use with
objectMapper.typedWriter(MyInterface.class).writeValue(....)
Jackson's VisibilityChecker provides an easy way for filtering certain properties, especially because it allows you to test for visibility (equals "will be serialized or not") for each method/field individually.
At least this helps for the serialization phase.
Here is what I did (using Jackson version 1.9.11):
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.introspect.AnnotatedMethod;
import org.codehaus.jackson.map.introspect.VisibilityChecker;
public static class InterfaceVisibilityChecker extends VisibilityChecker.Std {
private final Set<Method> visibleMethods;
public InterfaceVisibilityChecker(Class<?>... clazzes) {
super(JsonAutoDetect.Visibility.PUBLIC_ONLY);
this.visibleMethods = new HashSet<>();
for (Class<?> clz : clazzes) {
this.visibleMethods.addAll(Arrays.asList(clz.getMethods()));
}
}
#Override
public boolean isGetterVisible(Method m) {
return super.isGetterVisible(m) && isVisible(m);
}
#Override
public boolean isGetterVisible(AnnotatedMethod m) {
return isGetterVisible(m.getAnnotated());
}
private boolean isVisible(Method m) {
for (Method visiMthd : visibleMethods) {
if (isOverwriteMethod(m, visiMthd)) return true;
}
return false;
}
private boolean isOverwriteMethod(Method subMethod, Method superMethod) {
// names must be equal
if (! subMethod.getName().equals(superMethod.getName())) return false;
// return types must be assignable
if (! superMethod.getReturnType().isAssignableFrom(subMethod.getReturnType())) return false;
// parameters must be equal
if (! Arrays.equals(subMethod.getParameterTypes(), superMethod.getGenericParameterTypes())) return false;
// classes must be assignable
return superMethod.getDeclaringClass().isAssignableFrom(subMethod.getDeclaringClass());
}
}
The main idea is to use the standard VisibilityChecker and extend it by a check whether the method is declared in one of the given interfaces.
The checker is applied to an ObjectMapper instance using the following snippet:
ObjectMapper om = new ObjectMapper();
om.setVisibilityChecker(new InterfaceVisibilityChecker(
I1.class,
I2.class,
Ia.class,
Ib.class,
Ic.class
));
Some comments on the solution above:
The checker is not complete, methods like isIsGetterVisible or isFieldVisible can be handled in a similar manner if needed.
isOverwriteMethod is not optimized at all, it's checks could be cached.

I have a question about OOP .I Need Your help !

Please see the code below :
package bk;
public class A {
protected void methodA() {
System.out.println("Calling the method A !");
}
}
// And I have an another package :
package com;
import bk.A;
public class B extends A {
public void methodB() {
System.out.println("Goi phuong thuc B !");
}
public static void main(String[] args) {
A a = new B();
a.methodA();
}
}
How can I allow a to call methodA()?
Cause methodA() is protected and it can be called within derived classes only. Change it to public if you want to call it like this
Protected methods can only be called from within the class itself, or from derived classes.
The a variable is declared as a variable of type A. Class A itself has no publicly available methodA, so you cannot call it.
Yes, you assign a new B instance to the a variable and the a.methodA() statement is inside the derived B class, but the compiler only sees that a is of type A. It could be any other subclass of A as well, in which case you still wouldn't have access to methodA.
You'll have to tell the compiler that the a variable is actually of type B. Then you will be able to call methodA, because you're calling it from within class B.
B a = new B();
You are trying to access methodA() like it is public. Declaring simply methodA() in the B class is fine, but you cannot do a.methodA().
Conversely if it wasn't a method and simply protected int a;
you could do
a = 1; in class B
but
A a = new A();
a.a = 1;
is not legal
A protected method is visible to inheriting classes, even not part of the same package. A package scope (default) method is not. That is the only difference between protected and package scope.
The theory is that someone extending your class with protected access knows more about what they are doing than someone who is merely using it with public access. They also need more access to your class’s inner workings. Other than that, protected behaves like default package access.