[#2578] - Anonymous classes in expressions

Category:
Bug report
Priority:
Urgent
Status:
Acknowledged
Project: Severity:
Minor
Resolution:
Won't Fix
Component: Reproducibility:
Always
Assigned to:
3

An expression as :

new Object() {
public int lastDayOfMonth(int month) {
Calendar gcal = Calendar.getInstance();
cal.set(Calendar.MONTH, month);
return cal.getMaximum(Calendar.DAY_OF_MONTH);
}
}.lastDayOfMonth(6)

is not working actually and throw an ClassDefNotFoundException at fill time. The reason is that compiler keeps only the bytecode of the last class it compile (see JRJdtCompiler.getCompilerRequestor(), the for() loop at the end of acceptResult() method of local anonymous class expending ICompilerRequestor). Here I focuse on JRJdtCompiler, but it is true for JRJavacCompiler, except it seems to be working with output class files instead of class bytecode.

So I made a (backward compatible) patch to make it work (diff with this morning's trunk), storing all bytecode in the JasperReport object, and loading all report's classes in the same JRClassLoader.

Please, is this patch an acceptable one ?

AttachmentSize
File multiple_classes_report.patch8.31 KB
emassip's picture
Joined: Apr 25 2007 - 7:21pm
Last seen: 5 days 6 hours ago

7 Comments:

#1

Ok, now this patch is 5 months old and is running for 2 at production level on the top of a jasperreports-2.0.3 release with no .

I do consider it is a bug, throwing an exception.

Could you please review this patch or at least assign it to someone ?

Thanks

#2

Hi,

In JasperReports, the report compilers are pluggable.
For a given expression language, you can associate a report compiler of your choice.
If you think the report compilers that are shipped with JasperReports are too limited for your needs, you can use a configuration property in the jasperreports.properties file so that all reports with language="java" be compiled by your enhanced report compiler. Just look at the default.jasperreports.properties file in the JR source code to see how we have mapped report compilers for Groovy and BeanShell.

In light of this, I don\'t see why this patch would be tracked as a bug here. Especially one with a high priority.

Historically, in JasperReports, we resisted requests for making report expression even more complicated than they are today.
People were asking us to allow writing not expressions, but blocks of code.
We did not accept this as a feature because it would have transformed our JRXML files into Java source code files.
It is always better to edit Java code in separate Java files, because you can use Java editors for that, with code completion capabilities, syntax check and validation. Why would someone put a lot of Java code into an XML file, without tools to edit them properly?
Since we want to discourage this, I don\'t see this feature request being accepted in the near future.
But you are free to use your own report compiler as you please and still be able to upgrade to newer JR versions, if you just make use of the report compiler pluggability I mentioned above.

I understand from your patch that you have made modifications in several classes and interfaces of the JR and not only to the report compiler implementation.
If that is the case, then I suggest you try to come up with a report compiler implementation that does not need to alter the structure of a compiled report object, because you would have problems upgrading in the future.

As long as you implement public interfaces from JR and make use configuration properties, you can plug your code and benefit from JR upgrades without a problem.

I hope this helps.
Teodor

#3

Thanks for the answer !

I do agree with you and I understand the choice of not extending java support in JR expressions, it is sure a better way to do than to write important java code in external .java files.

The reason I consider it is a bug is :

- this expression java code is compiled at the time the report is compiled
- it is not included in the report .jasper file but it may be, this is randomized by the way Jrdt compiler gets bytecode and write it in the .jasper file (takes last class bytecode from the classes array).
- an exception is raised at fill-time because of this.

What do you think ?

There may be simpler ways to fix this than the way I do this, for sure.

Btw, I will now have to write external Java code just to get last day of a month, because it is more important to allow upgrading of the jr library.

Thanks anyway

PS : sorry for the bad english

#4

I also believe it is a bug. If we are allowed to write expressions, conceptually anonymous classes should be available. I vote to have it fixed!

#5

I agree. I'm forced to run in Java 1.7 for a particular customer and do not have String.join() available. I also cannot add to their runtime JAR. Trying to write this in one line is not possible without an anonymous class. Unfortunately, I still get this Fill Error in 2015!

<textFieldExpression class="java.lang.String"><![CDATA[(new Object()
{
public String toString()
{
final List<String> list = $F{notes};
if (list == null || list.size() == 0)
return "";

final int length = list.size();
final StringBuilder result = new StringBuilder();
for (int i = 0; i < length; i ++)
{
if (i > 0)
result.append("< br />");
result.append(list.get(i));
} // ends for

return result.toString();
}

}).toString()]]></textFieldExpression>

#6
  • Assigned:nobody»

Many years have passed but maybe it will be helpful: java 8 lambdas will be compiled into private method, so you can use this expression in jasper:

((java.util.function.Function<Integer, Integer>) (p) -> {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.MONTH, p);
return cal.getMaximum(Calendar.DAY_OF_MONTH);
}).apply(6)

#7
  • Severity:Critical» Minor
  • Resolution:Open» Won't Fix

Thanks @leopard04, this ticket can be closed now.

Feedback
randomness