Jump to content
We've recently updated our Privacy Statement, available here ×

JRMapArrayDataSource field names for a JSON-derived data set


srhaque

Recommended Posts

I am new to Jaspersoft, but an experienced programmer. I have some data in a main report field which is in the form of a string-encoded JSON. In Java, the data looks like this:

jshell> datadata ==> "{"A": {"GP": ...}, "C": {"GP": "8333.33", ...}}"[/code]

For clarity, the the corresponding JSON is:

{"A": {"GP": ..., "LEL-YTD": ...}, "C": {"GP": ..., "LEL-YTD": ...}}"[/code]

For reporting, I need to flatten keys ("A" and "C" here) into the child dicts, and convert this into an array (one entry for each of A and C) like this:

[{"Letter": "A", "GP": ..., "LEL-YTD": ...}, {"Letter": "C", "GP": ..., "LEL-YTD": ...}]"[/code]

So, I defined a datasource to fetch the "parent_json" field, and map the content into the array-of-maps form using the following Java 10 code

...<import value="java.util.HashMap"/><import value="com.fasterxml.jackson.core.type.TypeReference"/><import value="com.fasterxml.jackson.databind.ObjectMapper"/><import value="net.sf.jasperreports.engine.*"/><import value="net.sf.jasperreports.engine.data.*"/>...<dataSourceExpression><![CDATA[    new JRMapArrayDataSource(        new HashMap<String, Map<String,String>>(            new ObjectMapper().readValue($F{parent_json}.getBytes("UTF-8"), new TypeReference<Object>(){})        ).        entrySet().        stream().        map(x -> x.getValue().put("Letter", x.getKey()) == "" ? x : x).        map(x -> x.getValue()).toArray()    )]]></dataSourceExpression>[/code]

which seems like it ought to work, except that when looked at in the Java debugger, the dataset field names are:

  • Incomplete; the original map had 9 keys and the transformed map therefore has 10, whereas the debugger shows only 8 fields.
  • Sometimes wrong. Of the 8 fields, 4 of them have recognisable names such as "LEL-YTD" and "Ee-YTD" wheras the other 4 are called "A_key", "M_key", "Z_key" and "J_key".

Outside the debugger, I've confirmed the names of the fields in Jaspersoft using <textFieldExpression><![CDATA["$F{A_key}"]]></textFieldExpression> and so on. Also, in jshell, the transformed data has the 10 fields I expect:

jshell> new HashMap<String, Map<String,String>>(new ObjectMapper().readValue(data.getBytes(), new TypeReference<Object>(){})).entrySet().stream().map(x->x.getValue().put("Letter",x.getKey())==""?x:x).map(x->x.getValue()).iterator().next().keySet()$35 ==> [GP, Er, Ee, GP-YTD, Ee-YTD, Er-YTD, LEL-YTD, LEL-PT-YTD, PT-UEL-YTD, Letter][/code]

Any thoughts as to what I might be doing wrong?

Thanks, Shaheed

P.S. I should add, when trying to use this datasource, even with one of the keys the Java debugger shows, I do get an error on the main P60 report like this:

Exception in thread "main" java.lang.NoClassDefFoundError: P60_1542977708345_445958$1 (wrong name: P60_1542977708345_445958)
       at java.base/java.lang.ClassLoader.defineClass1(Native Method)
       at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
       at net.sf.jasperreports.engine.util.JRClassLoader.loadClass(JRClassLoader.java:355)
       at net.sf.jasperreports.engine.util.JRClassLoader.loadClassFromBytes(JRClassLoader.java:279)
       at net.sf.jasperreports.engine.design.JRAbstractJavaCompiler.loadEvaluator(JRAbstractJavaCompiler.java:105)
       at net.sf.jasperreports.engine.design.JRAbstractCompiler.loadEvaluator(JRAbstractCompiler.java:351)
       at net.sf.jasperreports.engine.JasperCompileManager.getEvaluator(JasperCompileManager.java:381)
       at net.sf.jasperreports.engine.fill.JRFillDataset.createCalculator(JRFillDataset.java:487)
       at net.sf.jasperreports.engine.fill.BaseReportFiller.<init>(BaseReportFiller.java:168)
       at net.sf.jasperreports.engine.fill.JRBaseFiller.<init>(JRBaseFiller.java:273)
       at net.sf.jasperreports.engine.fill.JRVerticalFiller.<init>(JRVerticalFiller.java:79)
       at net.sf.jasperreports.engine.fill.JRFiller.createBandReportFiller(JRFiller.java:251)
       at net.sf.jasperreports.engine.fill.JRFiller.createReportFiller(JRFiller.java:272)
       at net.sf.jasperreports.engine.fill.JRFiller.fill(JRFiller.java:156)
       at net.sf.jasperreports.engine.fill.JRFiller.fill(JRFiller.java:145)
       at net.sf.jasperreports.engine.JasperFillManager.fill(JasperFillManager.java:758)
       at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:1074)
       at de.cenote.jasperstarter.Report.fillInternal(Report.java:312)
       at de.cenote.jasperstarter.Report.fill(Report.java:272)
       at de.cenote.jasperstarter.App.processReport(App.java:224)
       at de.cenote.jasperstarter.App.main(App.java:109)

but I assume that this is metrely a consequence of the datasource not working as expected.

Link to comment
Share on other sites

  • Replies 2
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

OK, I finally figured out that the field names were actually in the .jrxml I had inhierited (and not introspected from the sub dataset as I had guessed). So, I fixed them. However, now I am getting an exception similar to the one in the epilogue of my original post. The main difference is that I get multiple instances of this error on a preview run:

java.lang.NoClassDefFoundError: P60_1543155161004_307909 (wrong name: P60_1543155161004_307909$2)    at java.lang.ClassLoader.defineClass1(Native Method)    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)    at net.sf.jasperreports.engine.util.JRClassLoader.loadClass(JRClassLoader.java:338)    at net.sf.jasperreports.engine.util.JRClassLoader.loadClassFromBytes(JRClassLoader.java:262)    at net.sf.jasperreports.engine.design.JRAbstractJavaCompiler.loadEvaluator(JRAbstractJavaCompiler.java:105)    at net.sf.jasperreports.engine.design.JRAbstractCompiler.loadEvaluator(JRAbstractCompiler.java:351)    at net.sf.jasperreports.engine.JasperCompileManager.getEvaluator(JasperCompileManager.java:381)    at net.sf.jasperreports.engine.fill.JRFillDataset.createCalculator(JRFillDataset.java:487)    at net.sf.jasperreports.engine.fill.JRFillDataset.createCalculator(JRFillDataset.java:477)    at net.sf.jasperreports.engine.fill.JRParameterDefaultValuesEvaluator.evaluateParameterDefaultValues(JRParameterDefaultValuesEvaluator.java:82)    at com.jaspersoft.studio.utils.ExpressionUtil.initBuiltInParameters(ExpressionUtil.java:399)    at com.jaspersoft.studio.editor.preview.view.control.ReportController$1.run(ReportController.java:381)    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:56)[/code]

I'd appreciate any insights on offer (and am happy to provide the .jrxml and .json data files as needed).

Link to comment
Share on other sites

OK, from what I can see in the debugger, I *think* Jaspersoft is getting confused between the loaded bytecode for the main and child datasets. The first clue for this is actually in the exception message: note how the error message refers to "name$2" and "name": IIRC, this is typically used for nested classes. The second clue is that in the debugger, when I step into JRClassLoader.loadClass for the main dataset, the byte array containing the class code, when viewed as text looks like this:

����   4 P60_1543161222131_631751$1 -com/fasterxml/jackson/core/type/TypeReference this$0 LP60_1543161222131_631751; <init> (LP60_1543161222131_631751;)V Code    
 
()V LineNumberTable
SourceFile P60_1543161222131_631751     Signature �Lcom/fasterxml/jackson/core/type/TypeReference<Ljava/util/HashMap<Ljava/lang/String;Ljava/util/Map<Ljava/lang/String;Ljava/lang/String;>;>;>; EnclosingMethod evaluate (I)Ljava/lang/Object; InnerClasses                   &

Note the reference to "HashMap<Ljava/lang/String;Ljava/util/Map<Ljava/lang/String;Ljava/lang/String;>;>;>". This is part of the definition for the sub dataset, NOT the main dataset. Of course this is just a guess on my part, but I am really beyond my rusty knowledge of Java...

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...