raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.28k stars 807 forks source link

Can't resolve type description, when Byte-buddy works with groovy #373

Closed wu-sheng closed 6 years ago

wu-sheng commented 7 years ago

Hi raphw. Skywalking is facing an error when our agent runs in an application based on groovy tech-stack. Cannot resolve type description for org.ofbiz.service.engine.GroovyBaseScript exception occurs. I guess the reason is Byte-buddy did some checks for classes, or groovy enging compiling output classes contains something unexpected.

import org.ofbiz.base.util.Debug; import org.ofbiz.service.ServiceUtil import org.ofbiz.service.ExecutionServiceException

abstract class GroovyBaseScript extends Script { public static final String module = GroovyBaseScript.class.getName();

Map runService(String serviceName, Map inputMap) throws ExecutionServiceException {
    if (!inputMap.userLogin) {
        inputMap.userLogin = this.binding.getVariable('parameters').userLogin;
    }
    Map result = binding.getVariable('dispatcher').runSync(serviceName, inputMap);
    if (ServiceUtil.isError(result)) {
        throw new ExecutionServiceException(ServiceUtil.getErrorMessage(result))
    }
    return result;
}

Map makeValue(String entityName) throws ExecutionServiceException {
    return result = binding.getVariable('delegator').makeValue(entityName);
}

Map findOne(String entityName, Map inputMap) {
    Map genericValue = binding.getVariable('delegator').findOne(entityName, inputMap, true);
    // TODO: get the list of pk fields from the map and use them only
    return genericValue;
}

List findList(String entityName, Map inputMap) {
    List genericValues = binding.getVariable('delegator').findByAnd(entityName, inputMap, null, false);
    // TODO: get the list of entity fields from the map and use them only
    return genericValues;
}

def success(String message) {
    // TODO: implement some clever i18n mechanism based on the userLogin and locale in the binding
    if (this.binding.hasVariable('request')) {
        // the script is invoked as an "event"
        if (message) {
            this.binding.getVariable('request').setAttribute("_EVENT_MESSAGE_", message)
        }
        return 'success';
    } else {
        // the script is invoked as a "service"
        if (message) {
            return ServiceUtil.returnSuccess(message);
        } else {
            return ServiceUtil.returnSuccess();
        }
    }
}
Map failure(String message) {
    // TODO: implement some clever i18n mechanism based on the userLogin and locale in the binding
    if (message) {
        return ServiceUtil.returnFailure(message);
    } else {
        return ServiceUtil.returnFailure();
    }
}
def error(String message) {
    // TODO: implement some clever i18n mechanism based on the userLogin and locale in the binding
    if (this.binding.hasVariable('request')) {
        // the script is invoked as an "event"
        if (message) {
            this.binding.getVariable('request').setAttribute("_ERROR_MESSAGE_", message)
        }
        return 'error';
    } else {
        if (message) {
            return ServiceUtil.returnError(message);
        } else {
            return ServiceUtil.returnError();
        }
    }
}
def logInfo(String message) {
    Debug.logInfo(message, module);
}
def logWarning(String message) {
    Debug.logWarning(message, module);
}
def logError(String message) {
    Debug.logError(message, module);
}

}


**And this error occurs AGAIN** in [drools](https://github.com/kiegroup/drools) , which manipulates classes by asm.

ERROR 2017-11-08 16:14:45 SkyWalkingAgent : Failed to enhance class com.xu.drools.Rule_22146222303DefaultConsequenceInvoker java.lang.IllegalStateException: Cannot resolve type description for org.drools.core.rule.builder.dialect.asm.ConsequenceStub



The origin issues from skywalking: https://github.com/OpenSkywalking/skywalking/issues/578 https://github.com/OpenSkywalking/skywalking/issues/555 . (Chinese descriptions, sorry)
raphw commented 6 years ago

It seems like it is not possible to read the class file for org.ofbiz.service.engine.GroovyBaseScript. Byte Buddy is asked to instrument all classes that have a certain super type and for this purpose, it needs to read all class files that are involved in a class's hierarchy.

With the mentioned class, in order to apply the check, it is necessary to parse its class file to find the class's super types. Without that information, Byte Buddy cannot check what super types the class has and answer the matching request.

To resolve this, you can either check how to better extract class files from specific types of class loaders (by default, the class loader is queried using getResourceAsStream) or you can handle the error by adding another matcher that excludes the type explicitly or by some other criteria. You can also wrap the matcher to suppress the exception.

wu-sheng commented 6 years ago

I am not sure how.to wrap the matcher to suppress the exception.Can you give me something more explicit or some examples?

raphw commented 6 years ago

The easiest way is to use ElementMatchers.failSafe(...) but this swallows the exception. Maybe you want to log the error and then you would need to implement something similar yourself.

wu-sheng commented 6 years ago

I found ElementMatchers.failSafe(...), but how can I log the exception? Can't find the callback.

wu-sheng commented 6 years ago

I think I get the point.

wu-sheng commented 6 years ago

Implement my own FailSafeMatcher would help.

raphw commented 6 years ago

I also think that is the best solution for something that custom.