JasperReports: Struts plugin pass a Map as a Parameter - struts2

This is my first question here!
I am trying to pass a Map as parameter from a struts action to a report. I have inserted the map in the reportParameters map that are being passed to the jrxml file.
My question is whether this Map can be retrieved inside the jrxml file.
To be More precise, I declare it like this:
<parameter name="reportParams.testMap" class="java.util.Map"/>
and I want to use it like this:
<textField>
<reportElement style="StyleData" x="240" y="0" width="100" height="23"/>
<textElement textAlignment="Left" verticalAlignment="Top"/>
<textFieldExpression><![CDATA[testMap.get("AR")]]></textFieldExpression>
</textField>
Is it possible? Because I keep getting this error in my application server logs:
No such property: testMap for class: Blank32A4_1336385977531_38171
Error evaluating expression : Source text : testMap.get("AR")
Error evaluating expression : Source text : testMap.get("AR")
My action class looks like this:
#Injectable
#Results({
#Result(name = "success", type = "jasper", params={"location",
"report.jasper",
"connection", "statsConnection",
"dataSource", "translations",
"reportParameters","reportParams",
"format","PDF"})
})
public class LocalMapStatisticNewAction extends ActionSupport{
...
public String execute() {
reportParams = new Hashtable<String, Object>();
testMap = new Hashtable<String, String>();
testMap.put("AR", "Argentina");
testMap.put("ES", "Spain");
reportParams.put("testMap", testMap);
//Jasper code here
}
...
public Map<String, Object> getReportParams() {
return reportParams;
}
}
Any hint would be helpful!

It looks like it could be as simple as you referencing a parameter by the wrong name.
testMap.get("AR")
You don't have a parameter called testMap. You have a parameter called reportParams.testMap. Also, you need to refer to parameters like this:
$P{testMap}.get("AR")
Rename the parameter or rename the reference to the parameter, and you should be OK.

Related

How do i "just use" Thymeleaf?

i tried to find tutorials online, but i only found them in the context of web applications. in my case what i have is an html template that i want to fill "manually", meaning it should run from a static main method without spring or any other framework. just "plain thymeleaf"
i have for example a test html file containing:
<p th:text="#{test.message}">This is a report</p>
how does the java code look like that simply fills this variable? i couldn't find a minimal running code example.
The following is a standalone Thymeleaf demo (no web application needed; no Spring used):
Assumptions:
I have a messages file called test.properties containing the following:
test.message=This is a message to you.
I have a related HTML template called test.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<p th:text="#{test.message}">This is a report</p>
<p th:text="${note}">This is a note</p>
</html>
In the above template, I added Thymeleaf variable expression (${note}), as well as the message expression - just to make the demo more complete. You may not even need that.
You need to make sure that the HTML template and the properties file are in the same location, because I am using the StandardMessageResolver - see below.
I created a standalone Thymeleaf template engine class:
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.thymeleaf.context.Context;
import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect;
import org.thymeleaf.messageresolver.IMessageResolver;
import org.thymeleaf.messageresolver.StandardMessageResolver;
import java.util.Map;
public class HtmlTemplateEngine {
private final TemplateEngine templateEngine;
public HtmlTemplateEngine() {
templateEngine = new org.thymeleaf.TemplateEngine();
templateEngine.addDialect(new Java8TimeDialect()); // optional extra
ClassLoaderTemplateResolver templateResolver
= new ClassLoaderTemplateResolver(Thread
.currentThread().getContextClassLoader());
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setPrefix("/thymeleaf/");
templateResolver.setCacheTTLMs(3600000L); // one hour
templateResolver.setCacheable(true);
templateResolver.setCharacterEncoding("UTF-8");
templateEngine.setTemplateResolver(templateResolver);
IMessageResolver messageResolver = new StandardMessageResolver();
templateEngine.setMessageResolver(messageResolver);
}
// use this if you do not want to pass a Context (see below). It basically does
// the same as the Context-based example, by transferring Map data to a Context:
public String getTemplate(String templateName, Map<String, Object> parameters) {
Context ctx = new Context();
if (parameters != null) {
parameters.forEach((k, v) -> {
ctx.setVariable(k, v);
});
}
return this.templateEngine.process(templateName, ctx).trim();
}
public String getTemplate(String templateName, Context ctx) {
return this.templateEngine.process(templateName, ctx).trim();
}
}
Some of the entries are default values - so they could be removed without affecting anything (for example the StandardMessageResolver will be used by default if you do not provide one).
I chose to use a ClassLoaderTemplateResolver. There are other choices you can make.
I use the above artifacts as follows:
private void processSimpleReport() {
Map<String, Object> model = new HashMap<>();
model.put("note", "my note here");
Context ctx = new Context();
//ctx.setLocale(Locale.US); // optional for i18n
ctx.setVariables(model);
HtmlTemplateEngine engine = new HtmlTemplateEngine();
String s = engine.getTemplate("test.html", ctx);
System.out.println(s);
}
Your question only uses a message - the model variables are just optional extras I added for this demo.
The resulting HTML is:
<!DOCTYPE html>
<html>
<p>This is a message to you.</p>
<p>my note here</p>
</html>

ImageBrush ImageSource x:Bind TargetNullValue different than datatamplate

So, I have a ListView that is x:Bind to a list and a DataTemplate.
The DataTemplate has an Elipse filled with an ImageBrush.
Everything works as it should but:
If an item in the list has a Null value for its string URL image property, the app crashes.
I have tried setting a TargetNullValue but my problem is that the X:DataType of the template is a class from an API, so I cant control it. I want to have an image as a default value in case the item has an image value of null.
In other words, if the item's image URL property is Null, I want XAML to load a predefined image from my Assets folder.
The problem is that because I have set my DataType as the class, anything I x:Bind to has to be within that class.
<Ellipse Width="40" Height="40">
<Ellipse.Fill>
<ImageBrush ImageSource="{x:Bind IconUrl, Mode=OneWay,TargetNullValue=/Assets/NoAvatarIcon.png}"/>
</Ellipse.Fill>
</Ellipse>
The above for example doesn't work for a Null string in ImageSource as the Path is set to the Class.
Right? Any workarounds?
The FallbackValue in Binding and x:Bind is different.
In Binding, FallbackValue is the value to use when the binding is unable to return a value.
A binding uses FallbackValue for cases where the Path doesn't evaluate on the data source at all, or if attempting to set it on the source with a two-way binding throws an exception that's caught by the data binding engine. FallbackValue is also used if the source value is the dependency property sentinel value DependencyProperty.UnsetValue.
But in x:Bind, FallbackValue specifies a value to display when the source or path cannot be resolved. It can't work with DependencyProperty.UnsetValue.
For your scenario, you can use Converter to operate DependencyProperty.UnsetValue just like following code.
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
object res;
res = (value == null ? false : true) ? string.IsNullOrEmpty(value.ToString()) ? null : new BitmapImage(new Uri(value.ToString())) : null;
return res;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Usage in Xaml File
<Page.Resources>
<local:ImageConverter x:Key="cm" />
</Page.Resources>
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView x:Name="MyListView" ItemsSource="{x:Bind Items}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:HeadPhoto">
<Ellipse Width="40" Height="40">
<Ellipse.Fill>
<ImageBrush ImageSource="{x:Bind PicUri,TargetNullValue=/Assets/pic.png,Converter={StaticResource cm }}" />
</Ellipse.Fill>
</Ellipse>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Page>
Placeholder image effect.

Spring MVC: path variable {studentId} not displaying correctly

This really confuses me.
Instead of proper URL with the value of one path variable {studentId}:
"http://somedomain.com:8080/someWebApp/essays/main/student/25/activity/add" (where 25 is the value of path variable {studentId})
I get this in my URL:
"http://somedomain.com:8080/someWebApp/essays/main/student/%7BstudentId%7D/activity/add"
This is my controller method for displaying some testPage and it works fine:
#RequestMapping(value="/{studentId}/activity/add", method = RequestMethod.GET)
public String getForm(#PathVariable Integer studentId, Model model) {
StudentActivityDTO studentActivityDTO = new StudentActivityDTO();
Student student = studentService.get(studentId);
studentActivityDTO.setStudent(student);
studentActivityDTO.getActivity().setEssayFlag("Essay");
model.addAttribute("studentActivityDTO", studentActivityDTO);
model.addAttribute("courseList", courseService.getAll());
model.addAttribute("teacherList", teacherService.getAll());
return "testPage";
}
And this is post controller method where this problem happens:
#RequestMapping(value="/{studentId}/activity/add", method = RequestMethod.POST)
public String postForm(#ModelAttribute("studentActivityDTO") StudentActivityDTO studentActivityDTO,
#PathVariable Integer studentId,
Model model) {
logger.debug("Received request to add new activity to student");
Activity activity = studentActivityDTO.getActivity();
activityService.add(studentId, activity);
return "success/addActivitySuccess";
}
In the first case #PathVariable works fine, in the second case it gives this error:
Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "{studentId}"
Instead of some value of the {studentId} being in the URL, I get string "{studentId}".
Can someone please tell me why?
Update: This is the important part of the jsp page (it is a pretty big page):
<c:url var="studentUrl" value="/essays/main/student/{studentId}/activity/add" />
<form:form modelAttribute="studentActivityDTO" method="POST" action="${studentUrl}">
...
<input type="submit" value="Submit" />
</form:form>
Probably you wanted
<c:url var="studentUrl" value="/essays/main/student/${studentActivityDTO.student.id}/activity/add" />

Putting parameters in velocity context in Jira 4.4

I'm developing a plugin to display additional information related to a project.
So I'm developing a Project Tab Panel module but my page does not display the paramenters I put in the velocity context.
Here is the a part of plugin xml:
<project-tabpanel key="stats-tab-panel" name="Stats Tab Panel" i18n-name-key="stats-tab-panel.name" class="it.pride.jira.plugins.StatsTabPanel">
<description key="stats-tab-panel.description">The Stats Tab Panel Plugin</description>
<label key="stats-tab-panel.label"></label>
<order>10</order>
<resource type="velocity" name="view" location="templates/tabpanels/stats-tab-panel.vm"/>
Here instead the useful part of my class:
public class StatsTabPanel extends GenericProjectTabPanel {
public StatsTabPanel(JiraAuthenticationContext jiraAuthenticationContext,
FieldVisibilityManager fieldVisibilityManager) {
super(jiraAuthenticationContext, fieldVisibilityManager);
// TODO Auto-generated constructor stub
}
public String testvalue="112002";
#Override
public boolean showPanel(BrowseContext context){
return true;
}
#Override
public Map<String, Object> createVelocityParams (BrowseContext context) {
Map<String, Object> contextMap = createVelocityParams(context);
contextMap.put("testvalue", testvalue);
return contextMap;
}
}
So, as in this case, when i write `$testvalue in my template the number doesn't show up.
What am I doing wrong?
The problem is that the getHtml method that is used to return the HTML for the tab has a Map that is the Velocity context but only contains the params in the BrowseContext object. The way to fix this is to override createVelocityParams in your class, e.g.
protected Map createVelocityParams(final BrowseContext ctx) {
Map params = super.createVelocityParams(ctx);
params.put("myparam", "some value for it");
return params;
}
The problem is that method is protected so I ended up also overriding getHtml which calls createVelocityParams in a parent class.
Some Project tabs extend GenericProjectTabPanel but some such as SummaryProjectTabPanel.java seem to use UI Fragments. I suspect that Fragments is what things are moving towards.

Struts2 using Map in select tag

You can easily use a List in struts2 select tag, but is there a way to use Map in tag?? If it is possible please provide a sample code...
thanx !
In my action class
public class MyAction extends ActionSupport {
private Map<String, String> map;
public String execute() throws Exception {
map = new HashMap<String, String>();
map.put("abc", "abc");
map.put("xyz", "xyz");
return SUCCESS;
}
}
For the jsp mapped to success, use some thing like this
<s:select list = "map" name = "name" label = "Name" headerKey="" headerValue = "Enter Value"/>
It depends on what are you trying to do. Lacking details, I can only point you to the docs : the list attribute of the select tag is an ...
Iterable source to populate from. If
the list is a Map (key, value), the
Map key will become the option 'value'
parameter and the Map value will
become the option body.
Below in the same doc there is an example with a (literal, inline) map (Months).

Resources