net.sf.jasperreports.compilers.JRGroovyGenerator 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 .
*/
/*
* Contributors:
* Peter Severin - [email protected]
* Gaganis Giorgos - [email protected]
*/
package net.sf.jasperreports.compilers;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sf.jasperreports.annotations.properties.Property;
import net.sf.jasperreports.annotations.properties.PropertyScope;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRExpressionChunk;
import net.sf.jasperreports.engine.JRField;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JRVariable;
import net.sf.jasperreports.engine.design.JRSourceCompileTask;
import net.sf.jasperreports.engine.util.JRStringUtil;
import net.sf.jasperreports.properties.PropertyConstants;
/**
* @author Teodor Danciu ([email protected]), Peter Severin ([email protected])
*/
public class JRGroovyGenerator
{
/**
* Property that determines the maximum size of a generated groovy method
*/
@Property(
category = PropertyConstants.CATEGORY_COMPILE,
scopes = {PropertyScope.CONTEXT},
sinceVersion = PropertyConstants.VERSION_5_5_2,
valueType = Integer.class
)
public static final String PROPERTY_MAX_METHOD_SIZE = JRPropertiesUtil.PROPERTY_PREFIX + "compiler.max.groovy.method.size";
/**
*
*/
private static final int EXPR_MAX_COUNT_PER_METHOD = 40;
private static Map fieldPrefixMap;
private static Map variablePrefixMap;
private static Map methodSuffixMap;
static
{
fieldPrefixMap = new HashMap();
fieldPrefixMap.put(JRExpression.EVALUATION_OLD, "Old");
fieldPrefixMap.put(JRExpression.EVALUATION_ESTIMATED, "");
fieldPrefixMap.put(JRExpression.EVALUATION_DEFAULT, "");
variablePrefixMap = new HashMap();
variablePrefixMap.put(JRExpression.EVALUATION_OLD, "Old");
variablePrefixMap.put(JRExpression.EVALUATION_ESTIMATED, "Estimated");
variablePrefixMap.put(JRExpression.EVALUATION_DEFAULT, "");
methodSuffixMap = new HashMap();
methodSuffixMap.put(JRExpression.EVALUATION_OLD, "Old");
methodSuffixMap.put(JRExpression.EVALUATION_ESTIMATED, "Estimated");
methodSuffixMap.put(JRExpression.EVALUATION_DEFAULT, "");
}
/**
*
*/
protected final JRSourceCompileTask sourceTask;
private final ReportClassFilter classFilter;
private final int maxMethodSize;
protected Map parametersMap;
protected Map fieldsMap;
protected Map variablesMap;
protected JRVariable[] variables;
protected JRGroovyGenerator(JRSourceCompileTask sourceTask, ReportClassFilter classFilter)
{
this.sourceTask = sourceTask;
this.classFilter = classFilter;
this.parametersMap = sourceTask.getParametersMap();
this.fieldsMap = sourceTask.getFieldsMap();
this.variablesMap = sourceTask.getVariablesMap();
this.variables = sourceTask.getVariables();
JRPropertiesUtil properties = JRPropertiesUtil.getInstance(sourceTask.getJasperReportsContext());
maxMethodSize = properties.getIntegerProperty(PROPERTY_MAX_METHOD_SIZE, Integer.MAX_VALUE);
}
/**
*
*/
public static String generateClass(JRSourceCompileTask sourceTask) throws JRException
{
return generateClass(sourceTask, null);
}
public static String generateClass(JRSourceCompileTask sourceTask, ReportClassFilter classFilter) throws JRException
{
JRGroovyGenerator generator = new JRGroovyGenerator(sourceTask, classFilter);
return generator.generateClass();
}
protected String generateClass() throws JRException
{
StringBuilder sb = new StringBuilder();
generateClassStart(sb);
generateDeclarations(sb);
generateInitMethod(sb);
generateInitParamsMethod(sb);
if (fieldsMap != null)
{
generateInitFieldsMethod(sb);
}
generateInitVarsMethod(sb);
List expressions = sourceTask.getExpressions();
sb.append(this.generateMethod(JRExpression.EVALUATION_DEFAULT, expressions));
if (sourceTask.isOnlyDefaultEvaluation())
{
List empty = new ArrayList();
sb.append(this.generateMethod(JRExpression.EVALUATION_OLD, empty));
sb.append(this.generateMethod(JRExpression.EVALUATION_ESTIMATED, empty));
}
else
{
sb.append(this.generateMethod(JRExpression.EVALUATION_OLD, expressions));
sb.append(this.generateMethod(JRExpression.EVALUATION_ESTIMATED, expressions));
}
sb.append("}\n");
return sb.toString();
}
private void generateInitMethod(StringBuilder sb)
{
sb.append("\n");
sb.append("\n");
sb.append(" /**\n");
sb.append(" *\n");
sb.append(" */\n");
sb.append(" void customizedInit(\n");
sb.append(" Map pm,\n");
sb.append(" Map fm,\n");
sb.append(" Map vm\n");
sb.append(" )\n");
sb.append(" {\n");
sb.append(" initParams(pm);\n");
if (fieldsMap != null)
{
sb.append(" initFields(fm);\n");
}
sb.append(" initVars(vm);\n");
sb.append(" }\n");
sb.append("\n");
sb.append("\n");
}
protected final void generateClassStart(StringBuilder sb)
{
/* */
sb.append("/*\n");
sb.append(" * Generated by JasperReports - ");
sb.append((new SimpleDateFormat()).format(new java.util.Date()));
sb.append("\n");
sb.append(" */\n");
sb.append("import net.sf.jasperreports.engine.*;\n");
sb.append("import net.sf.jasperreports.engine.fill.*;\n");
sb.append("\n");
sb.append("import java.util.*;\n");
sb.append("import java.math.*;\n");
sb.append("import java.text.*;\n");
sb.append("import java.io.*;\n");
sb.append("import java.net.*;\n");
sb.append("\n");
/* */
String[] imports = sourceTask.getImports();
if (imports != null && imports.length > 0)
{
for (int i = 0; i < imports.length; i++)
{
sb.append("import ");
sb.append(imports[i]);
sb.append(";\n");
}
}
/* */
sb.append("\n");
sb.append("\n");
sb.append("/**\n");
sb.append(" *\n");
sb.append(" */\n");
sb.append("class ");
sb.append(sourceTask.getUnitName());
sb.append(" extends ");
String baseClass = classFilter != null && classFilter.isFilteringEnabled()
? "net.sf.jasperreports.compilers.GroovySandboxEvaluator"
: "net.sf.jasperreports.compilers.GroovyEvaluator";
sb.append(baseClass);
sb.append("\n{\n");
sb.append("\n");
sb.append(
" def methodMissing(String name, args) {\n" +
" return functionCall(name, args);\n" +
" }\n");
sb.append("\n");
sb.append(" /**\n");
sb.append(" *\n");
sb.append(" */\n");
}
protected final void generateDeclarations(StringBuilder sb)
{
if (parametersMap != null && parametersMap.size() > 0)
{
Collection parameterNames = parametersMap.keySet();
for (Iterator it = parameterNames.iterator(); it.hasNext();)
{
sb.append(" private JRFillParameter parameter_");
sb.append(JRStringUtil.getJavaIdentifier(it.next()));
sb.append(" = null;\n");
}
}
if (fieldsMap != null && fieldsMap.size() > 0)
{
Collection fieldNames = fieldsMap.keySet();
for (Iterator it = fieldNames.iterator(); it.hasNext();)
{
sb.append(" private JRFillField field_");
sb.append(JRStringUtil.getJavaIdentifier(it.next()));
sb.append(" = null;\n");
}
}
if (variables != null && variables.length > 0)
{
for (int i = 0; i < variables.length; i++)
{
sb.append(" private JRFillVariable variable_");
sb.append(JRStringUtil.getJavaIdentifier(variables[i].getName()));
sb.append(" = null;\n");
}
}
}
protected final void generateInitParamsMethod(StringBuilder sb) throws JRException
{
Iterator parIt = null;
if (parametersMap != null && parametersMap.size() > 0)
{
parIt = parametersMap.keySet().iterator();
}
else
{
Set emptySet = Collections.emptySet();
parIt = emptySet.iterator();
}
generateInitParamsMethod(sb, parIt, 0);
}
protected final void generateInitFieldsMethod(StringBuilder sb) throws JRException
{
Iterator fieldIt = null;
if (fieldsMap != null && fieldsMap.size() > 0)
{
fieldIt = fieldsMap.keySet().iterator();
}
else
{
Set emptySet = Collections.emptySet();
fieldIt = emptySet.iterator();
}
generateInitFieldsMethod(sb, fieldIt, 0);
}
protected final void generateInitVarsMethod(StringBuilder sb) throws JRException
{
Iterator varIt = null;
if (variables != null && variables.length > 0)
{
varIt = Arrays.asList(variables).iterator();
}
else
{
List emptyList = Collections.emptyList();
varIt = emptyList.iterator();
}
generateInitVarsMethod(sb, varIt, 0);
}
/**
*
*/
private void generateInitParamsMethod(StringBuilder sb, Iterator it, int index) throws JRException
{
sb.append(" /**\n");
sb.append(" *\n");
sb.append(" */\n");
sb.append(" void initParams");
if(index > 0)
{
sb.append(index);
}
sb.append("(Map pm)\n");
sb.append(" {\n");
for (int i = 0; i < EXPR_MAX_COUNT_PER_METHOD && it.hasNext(); i++)
{
String parameterName = it.next();
sb.append(" parameter_");
sb.append(JRStringUtil.getJavaIdentifier(parameterName));
sb.append(" = (JRFillParameter)pm.get(\"");
sb.append(JRStringUtil.escapeJavaStringLiteral(parameterName));
sb.append("\");\n");
}
if(it.hasNext())
{
sb.append(" initParams");
sb.append(index + 1);
sb.append("(pm);\n");
}
sb.append(" }\n");
sb.append("\n");
sb.append("\n");
if(it.hasNext())
{
generateInitParamsMethod(sb, it, index + 1);
}
}
/**
*
*/
private void generateInitFieldsMethod(StringBuilder sb, Iterator it, int index) throws JRException
{
sb.append(" /**\n");
sb.append(" *\n");
sb.append(" */\n");
sb.append(" void initFields");
if(index > 0)
{
sb.append(index);
}
sb.append("(Map fm)\n");
sb.append(" {\n");
for (int i = 0; i < EXPR_MAX_COUNT_PER_METHOD && it.hasNext(); i++)
{
String fieldName = it.next();
sb.append(" field_");
sb.append(JRStringUtil.getJavaIdentifier(fieldName));
sb.append(" = (JRFillField)fm.get(\"");
sb.append(JRStringUtil.escapeJavaStringLiteral(fieldName));
sb.append("\");\n");
}
if(it.hasNext())
{
sb.append(" initFields");
sb.append(index + 1);
sb.append("(fm);\n");
}
sb.append(" }\n");
sb.append("\n");
sb.append("\n");
if(it.hasNext())
{
generateInitFieldsMethod(sb, it, index + 1);
}
}
/**
*
*/
private void generateInitVarsMethod(StringBuilder sb, Iterator it, int index) throws JRException
{
sb.append(" /**\n");
sb.append(" *\n");
sb.append(" */\n");
sb.append(" void initVars");
if(index > 0)
{
sb.append(index);
}
sb.append("(Map vm)\n");
sb.append(" {\n");
for (int i = 0; i < EXPR_MAX_COUNT_PER_METHOD && it.hasNext(); i++)
{
String variableName = it.next().getName();
sb.append(" variable_");
sb.append(JRStringUtil.getJavaIdentifier(variableName));
sb.append(" = (JRFillVariable)vm.get(\"");
sb.append(JRStringUtil.escapeJavaStringLiteral(variableName));
sb.append("\");\n");
}
if(it.hasNext())
{
sb.append(" initVars");
sb.append(index + 1);
sb.append("(vm);\n");
}
sb.append(" }\n");
sb.append("\n");
sb.append("\n");
if(it.hasNext())
{
generateInitVarsMethod(sb, it, index + 1);
}
}
/**
*
*/
protected final String generateMethod(byte evaluationType, List expressionsList) throws JRException
{
StringBuilder sb = new StringBuilder();
if (expressionsList != null && !expressionsList.isEmpty())
{
sb.append(generateMethod(expressionsList.iterator(), evaluationType));
}
else
{
/* */
sb.append(" /**\n");
sb.append(" *\n");
sb.append(" */\n");
sb.append(" Object evaluate");
sb.append(methodSuffixMap.get(evaluationType));
sb.append("(int id)\n");
sb.append(" {\n");
sb.append(" return null;\n");
sb.append(" }\n");
sb.append("\n");
sb.append("\n");
}
return sb.toString();
}
/**
*
*/
private String generateMethod(Iterator it, byte evaluationType) throws JRException
{
int methodIndex = 0;
StringBuilder sb = new StringBuilder();
writeMethodHeader(sb, evaluationType, methodIndex);
++methodIndex;
StringBuilder methodBuffer = new StringBuilder();
StringBuilder expressionBuffer = new StringBuilder();
int methodExpressionIndex = 0;
while (it.hasNext())
{
JRExpression expression = it.next();
expressionBuffer.setLength(0);
writeExpression(expressionBuffer, expression, evaluationType);
if (methodExpressionIndex >= EXPR_MAX_COUNT_PER_METHOD //FIXME use a property for this
|| (methodExpressionIndex > 0 && methodBuffer.length() + expressionBuffer.length() > maxMethodSize))
{
// end the current method
//NB: relying on the fact that the expression ids are in ascending order
//FIXME investigate if using a main method that directly delegates to the other methods is better
writeNextMethodCall(sb, evaluationType, methodIndex, sourceTask.getExpressionId(expression));
sb.append(methodBuffer);
methodBuffer.setLength(0);
writeMethodEnd(sb);
// start a new method
writeMethodHeader(sb, evaluationType, methodIndex);
++methodIndex;
methodExpressionIndex = 0;
}
// write expression to current method
if (methodExpressionIndex > 0)
{
methodBuffer.append(" ");
methodBuffer.append("else ");
}
methodBuffer.append(expressionBuffer);
++methodExpressionIndex;
}
sb.append(" ");
sb.append(methodBuffer);
writeMethodEnd(sb);
return sb.toString();
}
protected void writeMethodHeader(StringBuilder sb, byte evaluationType, int methodIndex)
{
/* */
sb.append(" /**\n");
sb.append(" *\n");
sb.append(" */\n");
sb.append(" Object evaluate");
sb.append( methodSuffixMap.get(evaluationType));
if (methodIndex > 0)
{
sb.append(methodIndex);
}
sb.append("(int id)\n");
sb.append(" {\n");
sb.append(" Object value = null;\n");
sb.append("\n");
}
protected void writeMethodEnd(StringBuilder sb)
{
sb.append("\n");
sb.append(" return value;\n");
sb.append(" }\n");
sb.append("\n");
sb.append("\n");
}
protected void writeNextMethodCall(StringBuilder sb, byte evaluationType, int methodIndex, int startId)
{
sb.append(" if (id >= ");
sb.append(startId);
sb.append(")\n");
sb.append(" {\n");
sb.append(" value = evaluate");
sb.append(methodSuffixMap.get(evaluationType));
sb.append(methodIndex);
sb.append("(id);\n");
sb.append(" }\n");
sb.append(" else ");
}
protected void writeExpression(StringBuilder expressionBuffer, JRExpression expression, byte evaluationType)
{
expressionBuffer.append("if (id == ");
expressionBuffer.append(sourceTask.getExpressionId(expression));
expressionBuffer.append(")\n");
expressionBuffer.append(" {\n");
expressionBuffer.append(" value = (");
expressionBuffer.append(this.generateExpression(expression, evaluationType));
expressionBuffer.append(");\n");
expressionBuffer.append(" }\n");
}
/**
*
*/
private String generateExpression(
JRExpression expression,
byte evaluationType
)
{
StringBuilder sb = new StringBuilder();
JRExpressionChunk[] chunks = expression.getChunks();
if (chunks != null && chunks.length > 0)
{
for(int i = 0; i < chunks.length; i++)
{
JRExpressionChunk chunk = chunks[i];
String chunkText = chunk.getText();
if (chunkText == null)
{
chunkText = "";
}
switch (chunk.getType())
{
case JRExpressionChunk.TYPE_TEXT :
{
sb.append(chunkText);
break;
}
case JRExpressionChunk.TYPE_PARAMETER :
{
JRParameter jrParameter = parametersMap.get(chunkText);
sb.append("(");
if (!"java.lang.Object".equals(jrParameter.getValueClassName()))
{
sb.append("(");
sb.append(jrParameter.getValueClassName());
sb.append(")");
}
sb.append("parameter_");
sb.append(JRStringUtil.getJavaIdentifier(chunkText));
sb.append(".getValue())");
break;
}
case JRExpressionChunk.TYPE_FIELD :
{
JRField jrField = fieldsMap.get(chunkText);
sb.append("(");
if (!"java.lang.Object".equals(jrField.getValueClassName()))
{
sb.append("(");
sb.append(jrField.getValueClassName());
sb.append(")");
}
sb.append("field_");
sb.append(JRStringUtil.getJavaIdentifier(chunkText));
sb.append(".get");
sb.append(fieldPrefixMap.get(evaluationType));
sb.append("Value())");
break;
}
case JRExpressionChunk.TYPE_VARIABLE :
{
JRVariable jrVariable = variablesMap.get(chunkText);
sb.append("(");
if (!"java.lang.Object".equals(jrVariable.getValueClassName()))
{
sb.append("(");
sb.append(jrVariable.getValueClassName());
sb.append(")");
}
sb.append("variable_");
sb.append(JRStringUtil.getJavaIdentifier(chunkText));
sb.append(".get");
sb.append(variablePrefixMap.get(evaluationType));
sb.append("Value())");
break;
}
case JRExpressionChunk.TYPE_RESOURCE :
{
sb.append("str(\"");
sb.append(chunkText);
sb.append("\")");
break;
}
}
}
}
if (sb.length() == 0)
{
sb.append("null");
}
return sb.toString();
}
}