Hot questions for Using JasperReports in groovy

Question:

I want to create a variable $V{myMap} in iReport (3.7.3) and initialize a Map with this:

"key1":"value1","key2":"value2","key3:"value3" ...

Then in my report I will have a textField with this expression:

$V{myMap}.get("key1")

and i must to get

"value1"

What steps i must to follow to get that?


I read here:

How to use a java Hashmap as variable in JasperReport

these steps to set the variable properties:

set the following properties on the variable:

Name: myMap
Variable class: java.util.HashMap()
Reset type: None
Calculation: System
Variable expression: new java.util.HashMap()

But what about initialize it?

I know i can use groovy and use maps like in this article:

http://groovy.codehaus.org/Collections

But i dont' know which steps to follow.

Thanks in advance for share your knowledge!


Answer:

This is the method to create the variable

<variable name="myMap" class="java.util.HashMap" resetType="None" calculation="System">
    <variableExpression><![CDATA[['key1':'value1', 'key2':'value2', 'key3':'value3']]]></variableExpression>
</variable>

Then for use it:

$V{myMap}.get("key1")

Will get

value1

Question:

I have an Jasper report that put my data into csv and I need something like this:

$F{OBSERVATII}.split(" ").size()>=2 ? ($F{OBSERVATII}.split(" ")[0]+" "+$F{OBSERVATII}.split(" ")[1]+" "+$F{OBSERVATII}.split(" ")[2]) : $F{OBSERVATII}

but Jasper throws me an

Cannot invoke size() on the array type String[]

If I put only

$F{OBSERVATII}.split(" ")[0]+" "+$F{OBSERVATII}.split(" ")[1]+" "+$F{OBSERVATII}.split(" ")[2])

then, when I have an simple word string (without spaces) it gives me an error...


Answer:

Final Edit:

The correct syntax for Jasper Reports is this. Evidently Jasper does not like using the property .length in this context.

 Arrays.asList($F{OBSERVATII}.split(" ")).size() ? blah...

Don't you want the length property for an array of strings, rather than the size method which does not work with an array?

.length >= 2 ? blah

Edited to say:

You said Jasper does not like the above syntax, but it's what you should use. You could try:

(String[] $F{OBSERVATII}.split(" ")).length>=2 ? blah...

Or

Arrays.asList($F{OBSERVATII}.split(" ")).size() ? blah...

That will convert your array to a list and use the size method. I don't know if Jasper will like that or not, if not, I suppose their expression editor sucks.

Question:

I'm working in a desktop application for generating reports with Java Swing and Jasper Reports. Some days ago I ran into a problem because of a Groovy function that my code was not able to find. I found this answer and the problem was solved (note I left a comment) but when I packaged my application and tried to run it from the console I got the same issue. This is the stacktrace:

net.sf.jasperreports.engine.JRRuntimeException: Function MONTH not found.
    at net.sf.jasperreports.compilers.GroovyEvaluator.functionCall(GroovyEvaluator.java:106)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:210)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:59)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:154)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:174)
    at subReporteSummary_1502405767221_591326.methodMissing(calculator_subReporteSummary_1502405767221_591326:22)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:939)
    at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1262)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1215)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:154)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:166)
    at subReporteSummary_1502405767221_591326.evaluateEstimated(calculator_subReporteSummary_1502405767221_591326:336)
    at net.sf.jasperreports.engine.fill.JREvaluator.evaluateEstimated(JREvaluator.java:342)
    ... 14 more

But when I inspect the jar I'm able to find the MONTH function, which is in the net.sf.jasperreports.functions.standard.DateTimeFunctions class

@Function("MONTH")
@FunctionParameters({
    @FunctionParameter("dateObject")})
public static Integer MONTH(Object dateObject){
    return getCalendarFieldFromDate(dateObject,Calendar.MONTH)+1;
}

from the jasperreports-functions package which is in my classpath and is added to the package, as you may note by my maven configuration

<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <repositories>
        <!-- Jasper Reports repository to get japerreports-functions -->
        <repository>
            <id>jr-ce-releases</id>
            <url>http://jaspersoft.artifactoryonline.com/jaspersoft/jr-ce-releases</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>net.sf.jasperreports</groupId>
            <artifactId>jasperreports</artifactId>
            <version>6.4.0</version>
            <!-- Exclusions to avoid some JasperReports certificates problems -->
            <exclusions>
                <exclusion>
                    <groupId>org.bouncycastle</groupId>
                    <artifactId>bcmail-jdk14</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>bouncycastle</groupId>
                    <artifactId>bcmail-jdk14</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.bouncycastle</groupId>
                    <artifactId>bctsp-jdk14</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>bouncycastle</groupId>
                    <artifactId>bcprov-jdk14</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Groovy functions for Jasper Reports-->
        <dependency>
            <groupId>net.sf.jasperreports</groupId>
            <artifactId>jasperreports-functions</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.12</version>
        </dependency>

        <!-- Driver needed to connect to the DB -->
        <dependency>
            <groupId>com.ibm.informix</groupId>
            <artifactId>jdbc</artifactId>
            <version>4.10.8.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- This is to include all my dependencies in my package (it works fine) -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.0.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>ar.edu.unt.gui.MainFrame</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>

        <resources>
            <resource>
                <!-- I don't want to package the reports' source file -->
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>*.jrxml</exclude>
                </excludes>
            </resource>
        </resources>
    </build>
</project>

The MONTH function is called from a subreport. I found this post in the Jaspersoft Community but my report doesn't have such <returnValue> tag. This is the fragment from the main report where the subreport is declared:

<summary>
    <band height="239" splitType="Stretch">
        <subreport>
            <reportElement x="0" y="0" width="469" height="200" uuid="2da4b923-ee34-4a6d-9a04-8d050a2feb0f"/>
            <subreportParameter name="NRO_PAGINAS_PADRE">
                <subreportParameterExpression><![CDATA[$V{PAGE_NUMBER}]]></subreportParameterExpression>
            </subreportParameter>
            <connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
            <subreportExpression><![CDATA["subReporteSummary.jasper"]]></subreportExpression>
        </subreport>
        <textField evaluationTime="Auto">
            <reportElement x="175" y="219" width="126" height="20" uuid="28a4ff7e-d6dd-47f5-a655-5e0ea7bec50b"/>
            <textElement textAlignment="Center" verticalAlignment="Middle"/>
            <textFieldExpression><![CDATA["- Página " + $V{NRO_PAGINA_ACTUAL} + " de " + $V{PAGE_NUMBER} + " -"]]></textFieldExpression>
        </textField>
    </band>
</summary>

And this is the subReporteSummary.jrxml (summarySubreport in spanish) fragment where the MONTH function is called:

<variable name="NOMBRE_MES" class="java.lang.String" resetType="None">
    <variableExpression><![CDATA[MONTH($F{fechacancelacion}) == 1? "Enero" :
    MONTH($F{fechacancelacion}) == 2? "Febrero" :
    MONTH($F{fechacancelacion}) == 3? "Marzo" :
    MONTH($F{fechacancelacion}) == 4? "Abril" :
    MONTH($F{fechacancelacion}) == 5? "Mayo" :
    MONTH($F{fechacancelacion}) == 6? "Junio" :
    MONTH($F{fechacancelacion}) == 7? "Julio" :
    MONTH($F{fechacancelacion}) == 8? "Agosto" :
    MONTH($F{fechacancelacion}) == 9? "Septiembre" :
    MONTH($F{fechacancelacion}) == 10? "Octubre" :
    MONTH($F{fechacancelacion}) == 11? "Noviembre" : "Diciembre"]]></variableExpression>
    <initialValueExpression><![CDATA[MONTH($F{fechacancelacion}) == 1? "Enero" :
    MONTH($F{fechacancelacion}) == 2? "Febrero" :
    MONTH($F{fechacancelacion}) == 3? "Marzo" :
    MONTH($F{fechacancelacion}) == 4? "Abril" :
    MONTH($F{fechacancelacion}) == 5? "Mayo" :
    MONTH($F{fechacancelacion}) == 6? "Junio" :
    MONTH($F{fechacancelacion}) == 7? "Julio" :
    MONTH($F{fechacancelacion}) == 8? "Agosto" :
    MONTH($F{fechacancelacion}) == 9? "Septiembre" :
    MONTH($F{fechacancelacion}) == 10? "Octubre" :
    MONTH($F{fechacancelacion}) == 11? "Noviembre" : "Diciembre"]]></initialValueExpression>
</variable>

briefly: fechacancelacion is a java.util.Date variable and the expression is for get the month's names in upper case (is a requirement), which I can't get with a DATEFORMAT function because it gives me the names only in lowercase.

But getting back to the issue and to summarize, I have the MONTH function available in my JAR, the report compiles and shows correctly when I run my application from the IDE (Netbeans) but I'm getting an error running from the console with java -jar myapp-1.0.jar from the target folder.

If you need any other evidence, comment it out. Any help will be appreciated. Thanks in advance for your answers


Answer:

If you're using the maven shade plugin to package your jar, you'll have to merge jasperreports_extension.properties from all the jars as described here in order for JasperReports extensions (such as functions) to be registered properly.

Question:

I have the following value '4.6144444444' in the database as BigDecimal which conforms '04:36:51' in time pattern.

4.6144444444* 3600 0000 = 16611999.99984/1000 = 16611.99999984 seconds = 276.866666664 minutes.

This value 0.866666664*60 = 51.99999984 seconds also the total is '04:36:51.99999984'. Is there a way to cut the time value of '0.99999984' from '4.6144444444'?

Since I am adding up these values in the Jasper Report to calculate the sum.

0.1197222222 + 4.6144444444 + 0.7480555555 + 0.9475000000 = 6.4297222221 ==> 06:25:46 999 999 56

00:07:10 + 04:36:51 + 00:44:52 + 00:56:51 = 06:25:44

also there is two seconds difference in the result. Is there a way to manage that in Java or in Jasper?

Code

        def duration = rowTemp[7];
        def durationMiliseconds = duration * 3600000;
        def durationSeconds = durationMiliseconds/1000;
        def durationMinutes = (durationSeconds/60).toString();

        String[] durationMinutesSplitt = durationMinutes.split(".");
        def secondsPart = Double.parseDouble("0." + durationMinutesSplitt[1]);
        def secondWithMiliSeconds = secondsPart * 60;

In Jasper

In jasper I am rendering the vlaue as the following:

        <textField isStretchWithOverflow="true" isBlankWhenNull="true">
            <reportElement stretchType="RelativeToTallestObject" x="252" y="2" width="149" height="18" />
            <box topPadding="2" leftPadding="2" bottomPadding="2" rightPadding="2"/>
            <textElement textAlignment="Right" verticalAlignment="Middle">
                <font size="8" isBold="true" pdfFontName="Helvetica-Bold"/>
                <paragraph lineSpacing="Single"/>
            </textElement>
            <textFieldExpression><![CDATA[org.apache.commons.lang.time.DurationFormatUtils.formatDuration((long)$V{group1DurationStay}.doubleValue() * 3600000, "HH:mm:ss")]]></textFieldExpression>
        </textField>

Answer:

So floats are difficult cause they are not precise, but well, floats. A nice explanation can be found on e.g. wikipedia https://en.wikipedia.org/wiki/Floating-point_arithmetic.

In your case you would intuitively want to remove 0.99999984/3600=0.00027777773333333334 from the initial number, which gives 4.614166666666667. But that will result in 51.000000000001364 (because of how floats work).

If you just care about the final result, then consider

def duration = rowTemp[7];
def durationSeconds = duration*3600;
def durationMinutes = (durationSeconds/60);
def secondsPart = durationMinutes - floor(durationMinutes)
def secondWithMiliSeconds = secondsPart * 60;
def secondWithoutMiliSeconds = floor(secondsPart * 60);

(Code is untested)

Question:

I have a report with a subreport inside.

This subreport have property "Print when expresion" activated (a simple expression $field == string). It works fine, but if i change the "language" property in main report from "groovy" to "java", the subreport never appears

(I'm using IReports 5.6.0)


Answer:

With groovy you will compare two String's using ==

see Groovy - How to compare the string?

Instead in java you need to use .equals(), $field.equals(string)

see How do I compare strings in Java?