1717
1818package org .jboss .weld .bean .proxy .util ;
1919
20+ import static org .jboss .classfilewriter .AccessFlag .FINAL ;
21+ import static org .jboss .classfilewriter .AccessFlag .PUBLIC ;
22+ import static org .jboss .classfilewriter .AccessFlag .STATIC ;
23+ import static org .jboss .classfilewriter .AccessFlag .SUPER ;
24+ import static org .jboss .classfilewriter .AccessFlag .SYNTHETIC ;
25+ import static org .jboss .classfilewriter .util .DescriptorUtils .makeDescriptor ;
26+ import static org .jboss .weld .util .bytecode .BytecodeUtils .VOID_CLASS_DESCRIPTOR ;
27+
28+ import java .lang .invoke .MethodHandle ;
2029import java .lang .invoke .MethodHandles ;
30+ import java .lang .invoke .MethodType ;
2131import java .security .ProtectionDomain ;
2232import java .util .concurrent .ConcurrentHashMap ;
2333import java .util .concurrent .ConcurrentMap ;
2434
35+ import org .jboss .classfilewriter .AccessFlag ;
36+ import org .jboss .classfilewriter .ClassFile ;
37+ import org .jboss .classfilewriter .code .CodeAttribute ;
38+ import org .jboss .weld .bean .proxy .DummyClassFactoryImpl ;
2539import org .jboss .weld .bean .proxy .ProxyFactory ;
2640import org .jboss .weld .logging .BeanLogger ;
41+ import org .jboss .weld .proxy .WeldClientProxy ;
2742import org .jboss .weld .serialization .spi .ProxyServices ;
2843
2944/**
@@ -135,6 +150,8 @@ private WeldProxyDeclaringCL returnWeldCL(ClassLoader loader) {
135150 private Class <?> defineWithMethodLookup (String classToDefineName , byte [] classBytes , Class <?> originalClass ,
136151 ClassLoader loader ) {
137152 Module thisModule = WeldDefaultProxyServices .class .getModule ();
153+ Module apiModule = WeldClientProxy .class .getModule ();
154+
138155 try {
139156 Class <?> lookupBaseClass ;
140157 try {
@@ -143,19 +160,85 @@ private Class<?> defineWithMethodLookup(String classToDefineName, byte[] classBy
143160 } catch (Exception e ) {
144161 lookupBaseClass = originalClass ;
145162 }
163+
164+ // Ensure we can read the other module, and the other module can read us
165+
146166 Module lookupClassModule = lookupBaseClass .getModule ();
147167 if (!thisModule .canRead (lookupClassModule )) {
148168 // we need to read the other module in order to have privateLookup access
149169 // see javadoc for MethodHandles.privateLookupIn()
150170 thisModule .addReads (lookupClassModule );
151171 }
172+
173+ try {
174+ // the other module needs to read us, since the proxy we are
175+ // about to generate inside that module uses our classes
176+
177+ MethodHandle ensureReadsMethod = null ;
178+ if (!lookupClassModule .canRead (thisModule )) {
179+ ensureReadsMethod = generateEnsureReadsMethod (lookupBaseClass );
180+ ensureReadsMethod .invoke (thisModule );
181+ }
182+
183+ if (!lookupClassModule .canRead (apiModule )) {
184+ if (ensureReadsMethod == null ) {
185+ ensureReadsMethod = generateEnsureReadsMethod (lookupBaseClass );
186+ }
187+ ensureReadsMethod .invoke (apiModule );
188+ }
189+ } catch (Throwable t ) {
190+ throw new RuntimeException (t );
191+ }
192+
152193 MethodHandles .Lookup lookup = MethodHandles .privateLookupIn (lookupBaseClass , MethodHandles .lookup ());
153194 return lookup .defineClass (classBytes );
154195 } catch (IllegalAccessException e ) {
155196 throw new RuntimeException (e );
156197 }
157198 }
158199
200+ private MethodHandle generateEnsureReadsMethod (Class <?> lookupBaseClass )
201+ throws IllegalAccessException , NoSuchMethodException {
202+ MethodHandles .Lookup privateLookup = MethodHandles .privateLookupIn (lookupBaseClass , MethodHandles .lookup ());
203+
204+ return privateLookup .findStatic (
205+ // Define a hidden helper class in the *target* module/package
206+ privateLookup .defineClass (generateReadsHelperBytes (lookupBaseClass )),
207+ "ensureReads" ,
208+ MethodType .methodType (void .class , Module .class ));
209+ }
210+
211+ private byte [] generateReadsHelperBytes (Class <?> lookupBaseClass ) {
212+ // Put helper in the same package as the base class so the private Lookup can define it
213+
214+ // Create class header
215+ ClassFile ensureReadsClassFile = new ClassFile (
216+ (lookupBaseClass .getPackage () == null ? "" : lookupBaseClass .getPackage ().getName () + "." ) + "Weld$ReadsHelper" ,
217+ AccessFlag .of (PUBLIC , FINAL , SUPER , SYNTHETIC ),
218+ Object .class .getName (),
219+ ProxyFactory .class .getClassLoader (),
220+ DummyClassFactoryImpl .INSTANCE );
221+
222+ // Create method header for "public static void ensureReads(Module other)"
223+ CodeAttribute code = ensureReadsClassFile .addMethod (
224+ AccessFlag .of (PUBLIC , STATIC ),
225+ "ensureReads" ,
226+ VOID_CLASS_DESCRIPTOR ,
227+ makeDescriptor (Module .class ))
228+ .getCodeAttribute ();
229+
230+ // Create code for the method body "MethodHandles.lookup().lookupClass().getModule().addReads(other);"
231+ code .invokestatic ("java/lang/invoke/MethodHandles" , "lookup" , "()Ljava/lang/invoke/MethodHandles$Lookup;" );
232+ code .invokevirtual ("java/lang/invoke/MethodHandles$Lookup" , "lookupClass" , "()Ljava/lang/Class;" );
233+ code .invokevirtual ("java/lang/Class" , "getModule" , "()Ljava/lang/Module;" );
234+ code .aload (0 ); // parameter: Module other
235+ code .invokevirtual ("java/lang/Module" , "addReads" , "(Ljava/lang/Module;)Ljava/lang/Module;" );
236+ code .pop ();
237+ code .returnInstruction ();
238+
239+ return ensureReadsClassFile .toBytecode ();
240+ }
241+
159242 /**
160243 * A class loader that should only be used to load Weld-prefixed proxies meaning those that have non-existent packages.
161244 * This is a workaround for JMPS approach ({@code MethodHandles.Lookup}) not being able to fulfil this scenario.
0 commit comments