byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

Use OnMethodEnter can not access complex object

Open MaLuxray opened this issue 1 year ago • 6 comments

In my java code

class KnowledgeSmsAdvice{
       private static final WechatMiniappFeature wechatMiniappFeature = new WechatMiniappFeatureImpl();

    @Advice.OnMethodEnter
    public static void onMethodEnter(@Advice.Origin Method method,
                                     @Advice.Argument(value = 0, optional = true, readOnly = false, typing = Assigner.Typing.DYNAMIC) Object argument) {
       if (argument == null) return;
        
       ***
         
       final String wechatMiniappName = wechatMiniappFeature.getWechatMiniappName(hospitalId);

       ***
    }
}

In my premain class


    public class PremainClass {
    public static void premain(String args, Instrumentation instrumentation) {
        Profile.inti(args);

        //
        AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, module, protectionDomain) ->
                builder.method(ElementMatchers.named("sendLoopMessageTask")).intercept(Advice.to(KnowledgeSmsAdvice.class));

        new AgentBuilder.Default()
                .type(ElementMatchers.named("com.companies.message.interfaces.controller.MessageTaskController"))
                .transform(transformer)
                .installOn(instrumentation);
         }
    }

but when i access sendLoopMessageTask this method get a exception


Handler dispatch failed; nested exception is java.lang.IllegalAccessError: tried to access field com.ipharmacare.mvp.agent.message.center.advice.KnowledgeSmsAdvice.wechatMiniappFeature from class com.companies.message.interfaces.controller.MessageTaskController
org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.IllegalAccessError: tried to access field com.ipharmacare.mvp.agent.message.center.advice.KnowledgeSmsAdvice.wechatMiniappFeature from class com.companies.message.interfaces.controller.MessageTaskController

why goto access com.companies.message.interfaces.controller.MessageTaskController.wechatMiniappFeature

MaLuxray avatar May 08 '23 09:05 MaLuxray

I think this is because your advice class and the field wechatMiniappFeature are not declared as public.

FrankChen021 avatar May 08 '23 12:05 FrankChen021

As pointed out, the code is more or less copy pasted. You can change this if you set inline = false by delegation. But you are responsible to make sure that the targeted code is visible, or that the accessed code is visible from the inlined block.

raphw avatar May 08 '23 21:05 raphw

PremainClass java code

   public class PremainClass {
       public static void premain(String args, Instrumentation instrumentation) {
           Profile.inti(args);

           AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, module, protectionDomain) ->
                  builder.method(ElementMatchers.named("sendLoopMessageTask")).intercept(Advice.to(KnowledgeSmsAdvice.class));

           new AgentBuilder.Default()
                   .type(ElementMatchers.named("com.companies.message.interfaces.controller.MessageTaskController"))
                   .transform(transformer)
                   .installOn(instrumentation);
        }
    }

KnowledgeSmsAdvice java code

    public class KnowledgeSmsAdvice {
        private static final String knowledgeSceneCode = "HOSPITAL_KNOWLEDGE_SMS";
        private static final WechatMiniappFeature wechatMiniappFeature = new WechatMiniappFeatureImpl();

        @Advice.OnMethodEnter
        public static void onMethodEnter(@Advice.Origin Method method,
                                        @Advice.Argument(value = 0, optional = true, readOnly = false, typing = Assigner.Typing.DYNAMIC) 
                                        Object argument) {
             if (argument == null) return;

             JSONObject reqJSON = JSON.parseObject(JSON.toJSONString(argument));

             String sceneCode = StringUtils.trimToNull(reqJSON.getString("sceneCode"));
             if (!StringUtils.equals(sceneCode, knowledgeSceneCode)) return;

             Long hospitalId = reqJSON.getLong("hospitalId");
             if (hospitalId == null) return;

             final String wechatMiniappName = wechatMiniappFeature.getWechatMiniappName(hospitalId);
             if (wechatMiniappName == null) return;

             final String targetSceneCode = WechatMiniappName.generateMessageScene(wechatMiniappName, 
                        knowledgeSceneCode);
             reqJSON.put("sceneCode", targetSceneCode);
        }
    }

agent method MessageTaskController java code

   @RequestMapping({"/provider/message/task/client"})
   @RestController
   public class MessageTaskController {
        private static final Logger log = LoggerFactory.getLogger(MessageTaskController.class);
        @Autowired
        MessageTaskService messageTaskService;
        @Autowired
        MessagePushWithJiGuangService messagePushWithJiGuangService;

        @PostMapping({"/sendLoopMessageTask"})
        public ServerResponse<String> sendLoopMessageTask(@RequestBody MessageTaskLoopVO messageTaskLoopVO) throws Exception {
             return ServerResponse.createBySuccess(this.messageTaskService.saveLoopMessageTask(messageTaskLoopVO));
        }
    }  

when i access sendLoopMessageTask method get a exception

@raphw

MaLuxray avatar May 09 '23 01:05 MaLuxray

As shown in the code above. Accessing the knowledgeSceneCode field was successful, but the wechatMiniappFeature field would result in an error

@raphw

MaLuxray avatar May 09 '23 01:05 MaLuxray

This is because final strings (and primitives) are inlined. The field access is eliminated by javac.

raphw avatar May 09 '23 10:05 raphw

You should change the annotation @advice.onMethodenter to@advice.onMethodente (inline = false)

RTxin avatar May 17 '23 03:05 RTxin