net.sf.jasperreports.engine.fill.JREvaluator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jasperreports Show documentation
Show all versions of jasperreports Show documentation
Free Java Reporting Library
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see .
*/
package net.sf.jasperreports.engine.fill;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import net.sf.jasperreports.annotations.properties.Property;
import net.sf.jasperreports.annotations.properties.PropertyScope;
import net.sf.jasperreports.compilers.DirectExpressionEvaluator;
import net.sf.jasperreports.compilers.DirectExpressionEvaluators;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.type.WhenResourceMissingTypeEnum;
import net.sf.jasperreports.functions.FunctionSupport;
import net.sf.jasperreports.properties.PropertyConstants;
/**
* Base class for the dynamically generated expression evaluator classes.
* This class also provides some built-in functions that will be described next.
* Built-in Functions
* Report expressions can perform method calls on various objects that are available during
* report filling, such as parameters, fields, or variable values, but can also call methods on
* a special object that is already available as the this
reference. This is the calculator
* object. It has public utility methods that are ready to use inside report expressions.
*
* Currently, there are only a few utility methods of the calculator object available as built-in
* functions inside report expressions. These are the following:
*
* msg
- this function offers a convenient way to format messages based on the current
* report locale, just as you would normally do when using a
* java.text.MessageFormat
instance. Furthermore, several signatures for this
* function take up to three message parameters in order to make the formatting
* functionality easier to use.
* str
- this function is the equivalent of the $R{}
syntax. It gives access
* to locale specific resources from the associated resource bundle.
*
*
*
* @author Lucian Chirita ([email protected])
*/
public abstract class JREvaluator implements DatasetExpressionEvaluator
{
public static final String EXCEPTION_MESSAGE_KEY_RESOURCE_NOT_FOUND = "fill.evaluator.resource.not.found";
/**
* The expression evaluation engine in JasperReports has always ignored java.lang.NullPointerException
* exceptions raised during expression evaluation. An expression raising NullPointerException is evaluated to null.
* However, in certain cases, users want to be able to track down the source of their NPE and this configuration
* property can be set to instruct the expression evaluation engine to treat NPEs just the way all other expression
* exceptions are treated.
* The default value of this configuration property is true, meaning NPEs are ignored.
* The property can be set globally, at report or at dataset level.
*/
@Property(
category = PropertyConstants.CATEGORY_FILL,
defaultValue = PropertyConstants.BOOLEAN_TRUE,
scopes = {PropertyScope.CONTEXT, PropertyScope.DATASET},
sinceVersion = PropertyConstants.VERSION_6_1_1,
valueType = Boolean.class
)
public static final String PROPERTY_IGNORE_NPE = JRPropertiesUtil.PROPERTY_PREFIX + "evaluator.ignore.npe";
/**
* The resource bundle parameter.
*/
private JRFillParameter resourceBundle;
/**
* The resource missing type.
*/
private WhenResourceMissingTypeEnum whenResourceMissingType;
/**
* The report Locale used when parsing the bundle message.
*/
private JRFillParameter locale;
/**
* The function objects.
*/
private Map functions;
/**
*
*/
private FillFunctionContext functionContext;
/**
*
*/
protected boolean ignoreNPE = true;
private DirectExpressionEvaluators directExpressionEvaluators;
/**
* Default constructor.
*/
protected JREvaluator()
{
}
public void setDirectExpressionEvaluators(DirectExpressionEvaluators directExpressionEvaluators)
{
this.directExpressionEvaluators = directExpressionEvaluators;
}
private DirectExpressionEvaluator directEvaluator(JRExpression expression)
{
return directExpressionEvaluators == null ? null
: directExpressionEvaluators.getEvaluator(expression);
}
/**
* Initializes the evaluator by setting the parameter, field and variable objects.
*
* @param parametersMap the parameters indexed by name
* @param fieldsMap the fields indexed by name
* @param variablesMap the variables indexed by name
* @param resourceMissingType the resource missing type
* @throws JRException
*/
@Override
public void init(
Map parametersMap,
Map fieldsMap,
Map variablesMap,
WhenResourceMissingTypeEnum resourceMissingType,
boolean ignoreNPE
) throws JRException
{
whenResourceMissingType = resourceMissingType;
this.ignoreNPE = ignoreNPE;
resourceBundle = parametersMap.get(JRParameter.REPORT_RESOURCE_BUNDLE);
locale = parametersMap.get(JRParameter.REPORT_LOCALE);
functions = new HashMap();
functionContext = new FillFunctionContext(parametersMap);
customizedInit(parametersMap, fieldsMap, variablesMap);
if (directExpressionEvaluators != null)
{
directExpressionEvaluators.init(this, parametersMap, fieldsMap, variablesMap);
}
}
/**
*
*/
@SuppressWarnings("unchecked")
public T getFunctionSupport(Class clazz)
{
String classId = clazz.getName();
if (!functions.containsKey(classId))
{
try
{
FunctionSupport functionSupport = clazz.getDeclaredConstructor().newInstance();
functionSupport.init(functionContext);
functions.put(classId, functionSupport);
}
catch (IllegalAccessException | InstantiationException
| NoSuchMethodException | InvocationTargetException e)
{
throw new JRRuntimeException(e);
}
}
return (T)functions.get(classId);
}
/**
* Constructs a message using a pattern with one parameter.
*
* @param pattern the message pattern
* @param arg0 the message parameter
* @return the constructed message
* @see MessageFormat#format(java.lang.Object[],java.lang.StringBuffer, java.text.FieldPosition)
*/
public String msg(String pattern, Object arg0)
{
return getMessageFormat(pattern).format(new Object[] { arg0 }, new StringBuffer(), null).toString();
}
/**
* Constructs a message using a pattern with two parameters.
*
* @param pattern the message pattern
* @param arg0 the first message parameter
* @param arg1 the second message parameter
* @return the constructed message
* @see MessageFormat#format(java.lang.Object[],java.lang.StringBuffer, java.text.FieldPosition)
*/
public String msg(String pattern, Object arg0, Object arg1)
{
return getMessageFormat(pattern).format(new Object[] { arg0, arg1 }, new StringBuffer(), null).toString();
}
/**
* Constructs a message using a pattern with three parameters.
*
* @param pattern the message pattern
* @param arg0 the first message parameter
* @param arg1 the second message parameter
* @param arg2 the third parameter
* @return the constructed message
* @see MessageFormat#format(java.lang.Object[],java.lang.StringBuffer, java.text.FieldPosition)
*/
public String msg(String pattern, Object arg0, Object arg1, Object arg2)
{
return getMessageFormat(pattern).format(new Object[] { arg0, arg1, arg2 }, new StringBuffer(), null).toString();
}
/**
* Constructs a message using a pattern with any number of parameters.
*
* @param pattern the message pattern
* @param args the message parameters
* @return the constructed message
* @see MessageFormat#format(java.lang.Object[],java.lang.StringBuffer, java.text.FieldPosition)
*/
public String msg(String pattern, Object... args)
{
return getMessageFormat(pattern).format(args, new StringBuffer(), null).toString();
}
/**
* Returns a string for a given key from the resource bundle associated with the evaluator.
*
* @param key the key
* @return the string for the given key
* @see ResourceBundle#getString(java.lang.String)
*/
public String str(String key)
{
String str = null;
try
{
str = ((ResourceBundle) resourceBundle.getValue()).getString(key);
}
catch (NullPointerException e) //NOPMD
{
if (ignoreNPE)
{
str = handleMissingResource(key, e);
}
else
{
throw e;
}
}
catch (MissingResourceException e)
{
str = handleMissingResource(key, e);
}
return str;
}
protected Object handleEvaluationException(JRExpression expression, Throwable e) throws JRExpressionEvalException
{
throw new JRExpressionEvalException(expression, e);
}
@Override
public Object evaluate(JRExpression expression) throws JRExpressionEvalException
{
Object value = null;
if (expression != null)
{
DirectExpressionEvaluator directEvaluator = directEvaluator(expression);
try
{
if (directEvaluator != null)
{
value = directEvaluator.evaluate();
}
else
{
value = evaluate(expression.getId());
}
}
catch (NullPointerException e) //NOPMD
{
if (!ignoreNPE) throw new JRExpressionEvalException(expression, e);
}
catch (OutOfMemoryError e)
{
throw e;
}
// we have to catch Throwable because there is no way we could modify the signature
// of the evaluate method, without breaking backward compatibility of compiled report templates
catch (Throwable e) //NOPMD
{
value = handleEvaluationException(expression, e);
}
}
return value;
}
@Override
public Object evaluateOld(JRExpression expression) throws JRExpressionEvalException
{
Object value = null;
if (expression != null)
{
DirectExpressionEvaluator directEvaluator = directEvaluator(expression);
try
{
if (directEvaluator != null)
{
value = directEvaluator.evaluateOld();
}
else
{
value = evaluateOld(expression.getId());
}
}
catch (NullPointerException e) //NOPMD
{
if (!ignoreNPE) throw new JRExpressionEvalException(expression, e);
}
catch (OutOfMemoryError e)
{
throw e;
}
// we have to catch Throwable because there is no way we could modify the signature
// of the evaluate method, without breaking backward compatibility of compiled report templates
catch (Throwable e) //NOPMD
{
value = handleEvaluationException(expression, e);
}
}
return value;
}
@Override
public Object evaluateEstimated(JRExpression expression) throws JRExpressionEvalException
{
Object value = null;
if (expression != null)
{
DirectExpressionEvaluator directEvaluator = directEvaluator(expression);
try
{
if (directEvaluator != null)
{
value = directEvaluator.evaluateEstimated();
}
else
{
value = evaluateEstimated(expression.getId());
}
}
catch (NullPointerException e) //NOPMD
{
if (!ignoreNPE) throw new JRExpressionEvalException(expression, e);
}
catch (OutOfMemoryError e)
{
throw e;
}
// we have to catch Throwable because there is no way we could modify the signature
// of the evaluate method, without breaking backward compatibility of compiled report templates
catch (Throwable e) //NOPMD
{
value = handleEvaluationException(expression, e);
}
}
return value;
}
/**
* Handles the case when a resource is missing.
*
* @param key
* the resource key
* @param e
* the exception
* @return the value to use for the resource
* @throws JRRuntimeException
* when the resource missing handling type is Error
*/
protected String handleMissingResource(String key, Exception e) throws JRRuntimeException
{
String str;
switch (whenResourceMissingType)
{
case EMPTY:
{
str = "";
break;
}
case KEY:
{
str = key;
break;
}
case ERROR:
{
throw
new JRRuntimeException(
EXCEPTION_MESSAGE_KEY_RESOURCE_NOT_FOUND,
new Object[]{key},
e);
}
case NULL:
default:
{
str = null;
break;
}
}
return str;
}
/**
* Initializes the parameters, fields and variables of the evaluator.
*
* @param parametersMap the parameters indexed by name
* @param fieldsMap the fields indexed by name
* @param variablesMap the variables indexed by name
* @throws JRException
*/
protected abstract void customizedInit(
Map parametersMap,
Map fieldsMap,
Map variablesMap
) throws JRException;
/**
* Evaluates an expression using current fields and variables values.
*
* @param id the expression id
* @return the result of the evaluation
* @throws Throwable
* @see net.sf.jasperreports.engine.JRExpression#EVALUATION_DEFAULT
* @see JRFillVariable#getValue()
* @see JRFillField#getValue()
*/
protected abstract Object evaluate(int id) throws Throwable; //NOSONAR
/**
* Evaluates an expression using old fields and variables values.
*
* @param id the expression id
* @return the result of the evaluation
* @throws Throwable
* @see net.sf.jasperreports.engine.JRExpression#EVALUATION_OLD
* @see JRFillVariable#getOldValue()
* @see JRFillField#getOldValue()
*/
protected abstract Object evaluateOld(int id) throws Throwable; //NOSONAR
/**
* Evaluates an expression using estimated variables values.
*
* @param id the expression id
* @return the result of the evaluation
* @throws Throwable
* @see net.sf.jasperreports.engine.JRExpression#EVALUATION_ESTIMATED
* @see JRFillVariable#getEstimatedValue()
*/
protected abstract Object evaluateEstimated(int id) throws Throwable; //NOSONAR
/**
*
*/
private MessageFormat getMessageFormat(String pattern)
{
MessageFormat messageFormat = new MessageFormat("");
messageFormat.setLocale((Locale)locale.getValue());
messageFormat.applyPattern(pattern);
return messageFormat;
}
}