in drools-mvel/src/main/java/org/drools/mvel/builder/MVELExprAnalyzer.java [86:236]
public static MVELAnalysisResult analyzeExpression(final PackageBuildContext context,
final String expr,
final BoundIdentifiers availableIdentifiers,
final Map<String, Class< ? >> localTypes,
String contextIdentifier,
Class kcontextClass) {
if ( expr.trim().length() <= 0 ) {
MVELAnalysisResult result = analyze( (Set<String>) Collections.EMPTY_SET, availableIdentifiers );
result.setMvelVariables( new HashMap<>() );
result.setTypesafe( true );
return result;
}
MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = true;
MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;
MVEL.COMPILER_OPT_ALLOW_RESOLVE_INNERCLASSES_WITH_DOTNOTATION = true;
MVEL.COMPILER_OPT_SUPPORT_JAVA_STYLE_CLASS_LITERALS = true;
MVELDialect dialect = (MVELDialect) context.getDialect( "mvel" );
ParserConfiguration conf = getMVELDialectRuntimeData(context).getParserConfiguration();
conf.setClassLoader( context.getKnowledgeBuilder().getRootClassLoader() );
// first compilation is for verification only
// @todo proper source file name
final ParserContext parserContext1 = new ParserContext( conf );
if ( localTypes != null ) {
for ( Entry entry : localTypes.entrySet() ) {
parserContext1.addInput( (String) entry.getKey(),
(Class) entry.getValue() );
}
}
if ( availableIdentifiers.getThisClass() != null ) {
parserContext1.addInput( "this",
availableIdentifiers.getThisClass() );
}
if ( availableIdentifiers.getOperators() != null ) {
for ( Entry<String, EvaluatorWrapper> opEntry : availableIdentifiers.getOperators().entrySet() ) {
parserContext1.addInput( opEntry.getKey(), opEntry.getValue().getClass() );
}
}
parserContext1.setStrictTypeEnforcement( false );
parserContext1.setStrongTyping( false );
Class< ? > returnType;
try {
returnType = MVEL.analyze( expr,
parserContext1 );
} catch ( Exception e ) {
BaseDescr base = (context instanceof RuleBuildContext) ? ((RuleBuildContext)context).getRuleDescr() : context.getParentDescr();
if ( e instanceof CompileException && e.getCause() != null && e.getMessage().startsWith( "[Error: null]" )) {
// rewrite error message in cause original message is null
e = new CompileException(e.getCause().toString(), ( (CompileException) e ).getExpr(), ( (CompileException) e ).getCursor(), e.getCause());
}
AsmUtil.copyErrorLocation(e, context.getParentDescr());
context.addError( new DescrBuildError( base,
context.getParentDescr(),
null,
"Unable to Analyse Expression " + expr + ":\n" + e.getMessage() ) );
return null;
}
Set<String> requiredInputs = new HashSet<>();
requiredInputs.addAll( parserContext1.getInputs().keySet() );
HashMap<String, Class< ? >> variables = (HashMap<String, Class< ? >>) ((Map) parserContext1.getVariables());
if ( localTypes != null ) {
for ( String str : localTypes.keySet() ) {
// we have to do this due to mvel regressions on detecting true local vars
variables.remove( str );
}
}
// MVEL includes direct fields of context object in non-strict mode. so we need to strip those
if ( availableIdentifiers.getThisClass() != null ) {
requiredInputs.removeIf( s -> PropertyTools.getFieldOrAccessor( availableIdentifiers.getThisClass(), s ) != null );
}
// now, set the required input types and compile again
final ParserContext parserContext2 = new ParserContext( conf );
parserContext2.setStrictTypeEnforcement( true );
parserContext2.setStrongTyping( true );
for ( String input : requiredInputs ) {
if ("this".equals( input )) {
continue;
}
if (WM_ARGUMENT.equals( input )) {
parserContext2.addInput( input, InternalWorkingMemory.class );
continue;
}
Class< ? > cls = availableIdentifiers.resolveType( input );
if ( cls == null ) {
if ( input.equals( contextIdentifier ) || input.equals( "kcontext" ) ) {
cls = kcontextClass;
} else if ( input.equals( "rule" ) ) {
cls = Rule.class;
} else if ( localTypes != null ) {
cls = localTypes.get( input );
}
}
if ( cls != null ) {
parserContext2.addInput( input, cls );
}
}
if ( availableIdentifiers.getThisClass() != null ) {
parserContext2.addInput( "this", availableIdentifiers.getThisClass() );
}
boolean typesafe = context.isTypesafe();
try {
returnType = MVEL.analyze( expr,
parserContext2 );
typesafe = true;
} catch ( Exception e ) {
// is this an error, or can we fall back to non-typesafe mode?
if ( typesafe ) {
BaseDescr base = (context instanceof RuleBuildContext) ? ((RuleBuildContext)context).getRuleDescr() : context.getParentDescr();
AsmUtil.copyErrorLocation(e, context.getParentDescr());
context.addError( new DescrBuildError( base,
context.getParentDescr(),
null,
"Unable to Analyse Expression " + expr + ":\n" + e.getMessage() ) );
return null;
}
}
if ( typesafe ) {
requiredInputs = new HashSet<>();
requiredInputs.addAll( parserContext2.getInputs().keySet() );
requiredInputs.addAll( variables.keySet() );
variables = (HashMap<String, Class< ? >>) ((Map) parserContext2.getVariables());
if ( localTypes != null ) {
for ( String str : localTypes.keySet() ) {
// we have to do this due to mvel regressions on detecting true local vars
variables.remove( str );
}
}
}
MVELAnalysisResult result = analyze( requiredInputs, availableIdentifiers );
result.setReturnType( returnType );
result.setMvelVariables( variables );
result.setTypesafe( typesafe );
return result;
}