How to use Map as dataset element in JasperReports? - java

I'm passing a parameter to Jasper which is a collection of Maps. I would like to use this collection as dataset for a table.
If I had a collection of normal Java objects I would do:
$F{description}
to get the field. I would like to do something like:
get(description)
or
values().get(1)
Is it possible to retrieve a map value in a table like this?

As I really wanted to keep the service generic I decided for dynamic class creation with Javassist. It's an ugly solution but at least it works.
HashMap<String, Object> element = (HashMap<String, Object>) ((ArrayCollection) v).get(0);
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Dynamic"+System.currentTimeMillis());
element.keySet().forEach(s -> {
try {
//need only Strings
ctClass.addField(CtField.make("public String "+s+";", ctClass));
ctClass.addMethod(CtMethod.make("public String get" + StringUtils.capitalize(s) + "() { return " + s + "; }", ctClass));
} catch (Exception e) {
e.printStackTrace();
}
});
Class clazz = ctClass.toClass();
ArrayList<Object> objects = new ArrayList<>();
((Collection) v).forEach(m -> {
HashMap<String, Object> hm = (HashMap<String, Object>) m;
try {
Object obj = clazz.newInstance();
element.keySet().forEach(s -> {
try {
obj.getClass().getDeclaredField(s).set(obj, hm.get(s));
} catch (Exception e) {
e.printStackTrace();
}
});
objects.add(obj);
} catch (Exception e) {
e.printStackTrace();
}
});
parameters.put(k, new JRBeanCollectionDataSource(objects));

Related

Java Nashorn build json array object in java can't find way

I try to create java json array ,
can't find any way to create them using Nashorn
i can create simple objects ...
private void createJsonObject() {
try {
final Map<String, Object> newMap = new HashMap<>();
newMap.put("foo",1);
newMap.put("bar", true);
ScriptObjectMirror json = (ScriptObjectMirror) this.engine.eval("JSON");
json.putAll(newMap);
this.engine.put("jsonObject", json);
String result = (String) this.engine.eval("JSON.stringify(jsonObject)");
System.out.println(result);
} catch (ScriptException e) {
e.printStackTrace();
}
}
Result : {"bar":true,"foo":1}
Here i try to create array but im getting empty json
private void createJsonObject() {
try {
List<String> returnList = new ArrayList<>();
returnList.add("x");
returnList.add("y");
ScriptObjectMirror json = (ScriptObjectMirror) this.engine.eval("JSON");
json.put("test",returnList);
this.engine.put("jsonObject", json);
String result = (String) this.engine.eval("JSON.stringify(jsonObject)");
System.out.println(result);
} catch (ScriptException e) {
e.printStackTrace();
}
}
Result: {}
The end goal is to build array of objects in memory using java native tools without using dependencies

Incompatible Type Error in Android Project

This is an Android project. I'm completely new to Java (just started learning). As stated in the title, I'm getting an Incompatible Type Error
I've attached the respective method here :
public void init(Map map) {
this.productIds = new ArrayList();
try {
if (map.containsKey("products")) {
for (Entry<String, Object> "//Error Lies here" entry : ((HashMap) map.get("products")).entrySet()) {
InAppProduct productId = new InAppProduct();
productId.productId = ((String) entry.getKey()).toLowerCase();
HashMap<String, Object> extraValues = (HashMap) entry.getValue();
if (extraValues.containsKey(ShareConstants.MEDIA_TYPE)) {
productId.productType = (String) extraValues.get(ShareConstants.MEDIA_TYPE);
}
if (extraValues.containsKey("days")) {
productId.days = ((Integer) extraValues.get("days")).intValue();
}
this.productIds.add(productId);
}
return;
}
this.productIds = new ArrayList(ConfigurationFetcher.this.mDefaultsDelegate.getDefaultsInAppPackages());
} catch (Exception e) {
e.printStackTrace();
}
}
The Error is :
Required Object but found Entry <String, Object>
Let me know if you need additional code or any details. Thank You.
Set is a generic type. It is a container that can contain any kind of object.
In your case, it seems that your Set contains Map.Entry<String, Object> objects but since you don't specify that anywhere, Java assumes your Set contains Objects (the Java class that all other classes derive from) and produces an Incompatible Type Error.
Here's a slightly altered version of your code that should work.
public void init(Map map) {
this.productIds = new ArrayList();
try {
if (map.containsKey("products")) {
// ***** We now specify the type of object that the Set contains.
Set<Map.Entry<String, Object>> entrySet = ((HashMap) hm.get("products")).entrySet();
for (Entry<String, Object> entry : entrySet) {
InAppProduct productId = new InAppProduct();
productId.productId = ((String) entry.getKey()).toLowerCase();
HashMap<String, Object> extraValues = (HashMap) entry.getValue();
if (extraValues.containsKey(ShareConstants.MEDIA_TYPE)) {
productId.productType = (String) extraValues.get(ShareConstants.MEDIA_TYPE);
}
if (extraValues.containsKey("days")) {
productId.days = ((Integer) extraValues.get("days")).intValue();
}
this.productIds.add(productId);
}
return;
}
this.productIds = new ArrayList(ConfigurationFetcher.this.mDefaultsDelegate.getDefaultsInAppPackages());
} catch (Exception e) {
e.printStackTrace();
}
}
map.get("products")).entrySet() is a set of products, each product is a Object, not Entry <String, Object>.
This should work:
public void init(Map map) {
this.productIds = new ArrayList();
try {
if (map.containsKey("products")) {
for (Object entry : ((HashMap) map.get("products")).entrySet()) {
InAppProduct productId = new InAppProduct();
productId.productId = ((String) entry.getKey()).toLowerCase();
HashMap<String, Object> extraValues = (HashMap) entry.getValue();
if (extraValues.containsKey(ShareConstants.MEDIA_TYPE)) {
productId.productType = (String) extraValues.get(ShareConstants.MEDIA_TYPE);
}
if (extraValues.containsKey("days")) {
productId.days = ((Integer) extraValues.get("days")).intValue();
}
this.productIds.add(productId);
}
return;
}
this.productIds = new ArrayList(ConfigurationFetcher.this.mDefaultsDelegate.getDefaultsInAppPackages());
} catch (Exception e) {
e.printStackTrace();
}
}

Saving Map In Gson

I would like to save/load a map/hashmap into gson without using reflection (Java 9 is restricting this). Also not sure if I can still use the TypeToken since it depends on the reflection libary.
private TestMap map = new TestMap();
//Using this as TestMap.class as The Type parm causes ClassCAstException
private class TestMap extends HashMap<Integer, TeleportDialog[]> {}
#Test
public void loadingMapAndCheckingValues(){
File file = new File("./data/saves/teleports/teleports.gson");
Gson gson = new GsonBuilder().create();
Type token = new TypeToken<Map<Integer, TeleportDialog[]>>(){}.getType(); //This Works but violates what I'm after.
try {
Map<Integer, TeleportDialog[]> map = gson.fromJson(new FileReader(file), token);
map.forEach((integer, dialogs) -> {
System.out.println("Key: " + integer);
for(TeleportDialog d : dialogs){
System.out.println(d);
}
});
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}

Getting List type of class from ParameterizedTypeImpl

I have a field of Map I am trying instantiate that looks like this
Map<Long, List<MyObj>>
The code to convert it is this
ParameterizedType targetMapParameterizedType = (ParameterizedType) targetMethodMap.get(targetMethodName).getGenericParameterTypes()[0];
Class<?> mapType = targetMethodMap.get(targetMethodName).getParameterTypes()[0];
if(mapType.isInterface()) {
newMap = new HashMap<Object, Object>();
} else {
try {
newMap = (Map<Object, Object>) mapType.newInstance();
} catch(Exception e) {
newMap = new HashMap<Object, Object>();
}
}
Class<?> targetKeyType = null;
Class<?> targetValueType = null;
try {
targetKeyType = (Class<?>)targetMapParameterizedType.getActualTypeArguments()[0];
} catch (ClassCastException cce) {
cce.printStackTrace();
}
try {
targetValueType = (Class<?>)targetMapParameterizedType.getActualTypeArguments()[1];
} catch (ClassCastException cce) {
cce.printStackTrace();
}
This is related to this post I read: ClassCastException While casting List<String> to Class<?>.
targetValueType
is a ParameterizedTypeImpl object. If I look at the value of that object in debug it looks like java.util.List(MyObj path).
How do "know" that the object is a list progromatically so I can do the conversion?
Update
This is an object factory that converts autogenerated domain objects from webservices to DTO domain objects. So the below code is generalized so that it should be able to handle any type of parameter.
The instantiation should look like this:
Map<Long, List<MyObj>> newMap;
...
if(mapType.isInterface()) {
newMap = new HashMap<Long, List<MyObj>>();
} else {
try {
newMap = (Map<Long, List<MyObj>>) mapType.newInstance();
} catch(Exception e) {
newMap = new HashMap<Long, List<MyObj>>();
}
}
I ended up with the following code
ParameterizedType targetMapParameterizedType = (ParameterizedType) targetMethodMap.get(targetMethodName).getGenericParameterTypes()[0];
Class<?> mapType = targetMethodMap.get(targetMethodName).getParameterTypes()[0];
if(mapType.isInterface()) {
newMap = new HashMap<Object, Object>();
} else {
try {
newMap = (Map<Object, Object>) mapType.newInstance();
} catch(Exception e) {
newMap = new HashMap<Object, Object>();
}
}
Class<?> targetKeyType = null;
Class<?> targetValueType = null;
try {
targetKeyType = (Class<?>)targetMapParameterizedType.getActualTypeArguments()[0];
} catch (ClassCastException cce) {
cce.printStackTrace();
}
if(targetMapParameterizedType.getActualTypeArguments()[1] instanceof ParameterizedType) {
ParameterizedType paramTypeImpl = (ParameterizedType) targetMapParameterizedType.getActualTypeArguments()[1];
Class<?> containerParam = (Class<?>) paramTypeImpl.getRawType();
if(containerParam.isInstance(new ArrayList<>()) && containerParam.isInterface()) {
containerParam = new ArrayList<>().getClass();
}
targetValueType = containerParam;
} else {
targetValueType = (Class<?>)targetMapParameterizedType.getActualTypeArguments()[1];
}
I had to get the raw type of the parameterizedTypeImple object. Then check if it was related to a list and an interface and use that as Class object.

Selectlist not populating with right json data

I would still need some help with my dynamic selectlist.
I have the sript:
function getMains(element) {
var subjectgroup = element.value;
var select_element;
select_element = '#mains';
$(select_element).html('');
$(select_element).append($("<option></option>").attr("value","none").html(""));
// $(select_element).append($("<option></option>").attr("value","all").html(""));
if (element.value==''||element.value=='none'||element.value=='all')
return;
$.ajax({
type: 'GET',
url: 'getmainsubjects.html',
dataType: 'json',
data: ({id:data}),
success: function(data) {
$.each(function(data) {
if (!subjectgroup) {
$(select_element).append($(" <option>").attr("value",data.id,"items",data).html(data.description));
} else {
$(select_element).append($("<option>").attr("value",data.id,"items",data).html(data.description));
}
});
},
error: function(data) {
//alert("This failed!");
}
});
}
$('select#subjectgroups').ready(function(){
$("select#subjectgroups").find("option").each(function(i) {
if ($(this).val()!='all'&&$(this).val()!='none') {
$(this).append( " " + $(this).val() );
}
});
});
$('select#mains').ready(function(){
$("select#mains").find("option").each(function(i) {
if ($(this).val()!='all'&&$(this).val()!='none') {
$(this).append( " " + $(this).val() );
}
});
});
And the method:
#RequestMapping(method = RequestMethod.GET, params="id", value = "/getmainsubjects")
#ResponseBody
public String getMainSubjects( #RequestParam("id") int id) {
List<MainSubjectsSimple> mains = database.getMainSubjectsSimple(id, Localization.getLanguage());
//System.out.println(mains.size());
HashMap hm = new HashMap();
for (MainSubjectsSimple mss: mains) {
try {
hm.put("id",mss.getId());
hm.put("description", mss.getDescription());
} catch (NoSuchMessageException e) {
//hm.add(Integer.valueOf(mss.getId().toString(), translate(mss.getTranslationCode(),new Locale("fi")));
}
}
String json = null;
String _json = null;
try {
_json = HtmlEntityEncoder.encode(JsonUtils.javaToStr(hm));
} catch (Exception e) {
}
return _json;
}
I think I'm not looping the right values. Mains selectlist should be populated based on other selectlist so that the object's id is the value and description the label. Right now calling the url written in script returns only first object as json, not all of them, and the objects are not shown in mains selectlist.
You are putting the same keys over and over again to the Map hm:
HashMap hm = new HashMap();
for (MainSubjectsSimple mss: mains) {
try {
hm.put("id",mss.getId());
hm.put("description", mss.getDescription());
} catch (NoSuchMessageException e) {
//hm.add(Integer.valueOf(mss.getId().toString(),
translate(mss.getTranslationCode(),new Locale("fi")));
}
}
You need to use different keys for each entry in mains or use a collection (e.g. ArrayList) of Maps. An example of the latter:
List hms = new ArrayList();
for (MainSubjectsSimple mss: mains) {
try {
HashMap hm = new HashMap();
hm.put("id",mss.getId());
hm.put("description", mss.getDescription());
hms.add(hm);
} catch (NoSuchMessageException e) {
//hm.add(Integer.valueOf(mss.getId().toString(), translate(mss.getTranslationCode(),new Locale("fi")));
}
}
...
try {
_json = HtmlEntityEncoder.encode(JsonUtils.javaToStr(hms));
} catch (Exception e) {
}
I'm not familiar with the utils (JsonUtils) you are using so this might not work directly but the principle is the same anyways.

Categories