Consider the following where availableExclusions is an array of Date objects.
<s:select listValue="(new java.text.SimpleDateFormat('MM/dd/yyyy')).format(new java.util.Date(#this[0].time))" size="25" id="inputExclusionDates" name="available" list="availableExclusions" multiple="true" cssClass="multi-select" />
I created the above in response to this question How would I format a list of dates within a struts 2 select tag? (and I also recommended that the other solution may be the better way to go). Regardless if using such long OGNL expression is a good idea or not, I can't see the need for: new java.util.Date(#this[0].time) despite creating that fragment out of frustration and to my surprise found it worked where the seemingly equivalent #this[0] did not (produced no output).
If we substitute in listValue="#this[0].class" we see what we would expect: class java.util.Date
Creating a new Date behaves as expected, and calling the deprecated properties of Date such as listValue="#this[0].day" produces the expected output.
Why must I use the redundant expression new java.util.Date(#this[0].time) instead of #this[0] in this select statement?
Using Struts 2.3.1.2
Because #this[0] is automatically converted to String. If you turn log level to debug you can see an exception message that's normally suppressed.
Related
I migrating a Vaadin 8 project to Vaadin 14 and i try to show HTML in a grid column.
I figured out, that i have to use a TemplateRenderer, but how can i use it?
Here is the code from Vaadin 8:
grid.addColumn(e -> {
return ((Data) e).getValues()[index];
}).setCaption(myCaption).setRenderer(new HtmlRenderer());
In Vaadin 14 i did this:
gird.addColumn(e -> {
return TemplateRenderer.<Data>of((String) e.getValues()[index])
}).setHeader(myCaption);
e.getValues()[index] includes HTML, for example: <FONT SIZE = 4 COLOR = BLACK> ⚫</FONT>
In Vaadin 14 it always returns com.vaadin.flow.data.renderer.
Before we get to how to use a TemplateRenderer with Grid, I first need to point out that what you're trying to do is potentially dangerous because of the way it can lead to XSS vulnerabilities if the HTML strings that you want to show may be supplied by application users.
Using the Html component is indeed one potential solution to this problem, but it causes some overhead because there will be one component instance in memory for each row in the grid. There's also the same problem with potentially causing XSS vulnerabilities.
The first thing to notice with TemplateRenderer is that the renderer needs to be supplied directly as a parameter to addColumn. Wrapping it in a lambda will instead use that lambda as a value provider, which means that the toString() value of the renderer instance will be used with the default plain text renderer.
All rows should use the same renderer instance, configured with the same template string. The trick is that you can pass the data to show as a per-row property that the template will render for you. The last piece of the puzzle is that the template syntax tries to protect you against accidental XSS vulnerabilities, so you need to use a slightly contrived syntax to actually make it render the data as HTML.
Putting everything together, and also using JSoup to remove any dangerous stuff from your HTML strings, the working solution looks like this:
grid.addColumn(TemplateRenderer
.<Data> of("<div inner-h-t-m-l='[[item.html]]'></div>")
.withProperty("html", e -> {
String unsafeHtml = e.getValues()[index];
String safeHtml = Jsoup.clean(unsafeHtml, Whitelist.basic());
return safeHtml;
})).setHeader(myCaption);
I found a solution.
Instead of using the TemplateRenderer I used a ComponentRenderer.
The migration documentation recomented to use a TempleteRenderer or an ComponentRenderer instead of the htmlRenderer.
https://vaadin.com/docs/v14/flow/migration/8-migration-example.html#step-4-product-grid
Here is the code that worked for me:
grid.addColumn(new ComponentRenderer<>(e -> {
String value = (String) e.getValues()[index];
return new Html(value);
})).setHeader(String.valueOf(col + 1));
Comparing your attempts with TemplateRenderer and the documentation, I would assume it will have to look like this:
grid.addColumn(e ->
TemplateRenderer.<Data>of("[[item.customValue]]")
.withProperty("customValue", (String) e.getValues()[index])
).setHeader(myCaption);
I want to generate date in the format 2019-03-28T15:30:59+12:00 using wiremock.
I tried:
"currentDateTime": "{{now timezone='Australia/Sydney' format='yyyy-MM-dd'T'HH:mm:ssZ'}}"
but, I get exception:
wiremock.com.github.jknack.handlebars.HandlebarsException: inline:
found: ''yyyy-MM-dd'T'HH:mm:ssZ'', expected: 'no viable alternative at
input ''yyyy-MM-dd'T'HH:mm:ssZ'''
I have also tried escaping both the quotes around T, but it does not work.
What I am doing wrong?
Try using following block of code. Working fine for me and probably the best way.
format='yyyy-MM-dd\'T\'HH:mm:ss.SSSXXX'
In case anyone else comes across this post in the future, the simplest (but hacky) solution that I used is to format the parts before and after the 'T' separately like so:
"currentDateTime": "{{now timezone='Australia/Sydney' format='yyyy-MM-dd'}}T{{now timezone='Australia/Sydney' format='HH:mm:ssZ'}}"
A simple workaround:
Declare a variable (myformat in the example)
{{#assign 'myformat'}}yyyy-MM-dd'T'HH:mm:ssZ{{/assign}}
Use it in the stub/mock
{{now format=myformat}}
A sample templated response is -
{
"time": "{{#assign 'myformat'}}yyyy-MM-dd'T'HH:mm:ssZ{{/assign}}{{now format=myformat}}"
}
References
How to use custom variables in Handlebars for WireMock
https://wiremock.org/studio/docs/response-templating/misc-helpers/#assignment
If you need to include the date in the ISO 8601 format, you can omit the format option:
{{now timezone='Australia/Sydney'}}
It will produce the following result: 2021-06-09T05:45:53+10:00. If you omit the timezone and just use {{now}} - it will produce a date in UTC: 2021-06-08T19:48:27Z.
For reference, you can check the RenderableDate class in wiremock
"body": "{\"datetime\": \"{{now format='yyyy-MM-dd\\'T\\'HH:mm:ss'}}\"}"
I'm trying to get Thymeleaf to build me a URL where the domain part is a parameter, some fragment is a literal string, and the query parameters are also parameterized.
The documentation offers some examples:
#{${myDomain}/literalUrl}
#{${myDomain}'/literalUrl'}
#{/literalUrl(query=${queryValue})}
#{'/literalUrl'(query=${queryValue})}
#{${myDomain}(query=${queryValue})}
or even
<a th:with="baseUrl=${myDomain}" th:href="#{${baseUrl}}(query=${queryValue})}">
Separately, all of these work well. But if I try to combine them, the domain part suddenly refuses to resolve:
#{${myDomain}/literalUrl(query=${queryValue})} and #{${myDomain}+'/literalUrl'+(query=${queryValue})} each resolve to ${myDomain}/literalUrl?query=queryValue, and
How do I get Thymeleaf to properly generate my url https://example.com/literalUrl?query=queryValue
Don't know if this is a legit solution for your problem, but if you concat the literalUrl with the first parameter, it will work. Down side: you need an additional model parameter.
<a th:href="#{${linkData+path}(q=${queryParam})}">some link</a>
gets
some link
with model params:
mv.addObject("linkData", "https://example.com");
mv.addObject("path", "/literalUrl");
mv.addObject("queryParam", "queryValue");
In my web application I'm trying to prevent users from inserting JavaScript in the freeText parameter when they're running a search.
To do this, I've written code in the header Velocity file to check whether the query string contains a parameter called freeText, and if so, use the replace method to replace the characters within the parameter value. However, when you load the page, it still displays the original query string - I'm unsure on how to replace the original query string with my new one which has the replaced characters.
This is my code:
#set($freeTextParameter = "$request.getParameter('freeText')")
freeTextParameter: $freeTextParameter
#if($freeTextParameter)
##Do the replacement:
#set($replacedQueryString = "$freeTextParameter.replace('confirm','replaced')")
replacedQueryString after doing the replace: $replacedQueryString
The query string now: $request.getQueryString()
The freeText parameter now: $request.getParameter('freeText')
#end
In the code above, the replacedQueryString variable has changed as expected (ie the replacement has been carried out as expected), but the $request.getQueryString() and $request.getParameter('freeText') are still the same as before, as if the replacement had never happened.
Seeing as there is a request.getParameter method which works fine for getting the parameters, I assumed there would be a request.setParameter method to do the same thing in reverse, but there isn't.
The Java String is an immutable object, which means that the replace() method will return an altered string, without changing the original one.
Since the parameters map given by the HttpServletRequest object cannot be modified, this approach doesn't work well if your templates rely on $request.getParameter('freeText').
Instead, if you rely on VelocityTools, then you can rather rely on $params.freeText in your templates. Then, you can tune your WEB-INF/tools.xml file to make this parameters map alterable:
<?xml version="1.0">
<tools>
<toolbox scope="request">
<tool key="params" readOnly="false"/>
...
</toolbox>
...
</tools>
(Version 2.0+ of the tools is required).
Then, in your header, you can do:
#set($params.freeText = params.freeText.replace('confirm','replaced'))
I managed to fix the issue myself - it turned out that there was another file (which gets called on every page) in which the $!request.getParameter('freeText')" variable is used. I have updated that file so that it uses the new $!replacedQueryString variable (ie the one with the JavaScript stripped out) instead of the existing "$!request.getParameter('freeText')" variable. This now prevents the JavaScript from being executed on every page.
So, this is the final working code in the header Velocity file:
#set($freeTextParameter = "$!m.request.httpRequest.getParameter('freeText')")
#if($freeTextParameter)
#set($replacedQueryString = "$freeTextParameter.replace('confirm','').replace('<','').replace('>','').replace('(','').replace(')','').replace(';','').replace('/','').replace('\"','').replace('&','').replace('+','').replace('script','').replace('prompt','').replace('*','').replace('.','')")
#end
any idea how (if even possible) to call java method with optional parameters from JSF page?
Iam using Java 7,JSF 2.1, EL 2.2 (Glassfish 3.1.2). Thanks in advance...
I got this exception
javax.el.ELException: /example.xhtml: wrong number of arguments
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
Page example
<h:outputText value="#{bean.methodWithParameters('key.en.currentDate', '2012-01-01', '00:00')}"/>
<h:outputText value="#{bean.methodWithParameters('key.en.currentTime', '12:00')}"/>
Bean example
public String methodWithParameters(String key, Object ... params) {
String langValue = LanguageBean.translate(key);
return String.format(langValue, params);
}
Properties example
key.en.currentDate=Today is %s and current time is %s.
key.en.currentTime=Current time is %s.
key.en.currentDate=Today is %1$s and current time is %2$s.
key.en.currentTime=Current time is %2$s.
Varargs is not supported in EL.
As to your concrete functional requirement, you're approaching this totally wrong. You should not reinvent internationalization/localization in JSF, but instead use the JSF-provided facilities. You should be using <resource-bundle> in faces-config.xml or <f:loadBundle> in Facelets file for this. This will load the files by ResourceBundle API and use the MessageFormat API to format the messages. You can then format the strings by <h:outputFormat> with <f:param>.
E.g. com/example/i18n/text.properties
key.en.currentDate=Today is {0} and current time is {1}.
key.en.currentTime=Current time is {0}.
View:
<f:loadBundle baseName="com.example.i18n.text" var="text" />
<h:outputFormat value="#{text['key.en.currentDate']}">
<f:param value="2012-01-01" />
<f:param value="00:00" />
</h:outputFormat>
Further I'm not sure if that en in the key stands for English or not, but if it indeed stands for the language, then you're making another mistake. The separate languages needs to have each its own properties file like text_en.properties, text_de.properties, etc conform ResourceBundle API rules.
See also:
Java EE 6 tutorial - Providing localized messages