My issue is quite simple : I want to create a composite component with a String attribute, Type.
<cc:attribute name="type" />
This attribute will have 3 acceptable values, [TYPE1, TYPE2, TYPE3]
Is it possible to say my component will accept only these values ?
Unfortunately no, you cannot put a compile/buildtime restriction on a composite component attribute value in the cc interface. You can however put a runtime restriction by checking the value in the cc implementation.
<ui:param name="type" value="#{cc.attrs.type}" />
<ui:fragment rendered="#{type == 'TYPE1' or type == 'TYPE2' or type == 'TYPE3'}">
<p>The type is TYPE1, TYPE2 or TYPE3.</p>
<p>Write your component's body here.</p>
</ui:fragment>
That'll be your best bet.
How can I concatenate the name of a property using the EL?
This is what I tried:
<ui:repeat value="#{someBean.getParts()}" var="part">
<h:inputTextarea value="#{someOtherBean.result}#{part}" />
</ui:repeat>
But it didn't work.
The bean has the four property resultA, resultB, resultC and resultD. getParts() returns "A", "B", "C", and "D".
It's quite possible though. You can use <ui:param> to prepare the dynamic property name and use the brace notation [] to access it.
<ui:repeat value="#{someBean.parts}" var="part">
<ui:param name="resultPart" value="result#{part}" />
<h:inputTextarea value="#{someOtherBean[resultPart]}" />
</ui:repeat>
Needless to say that I agree with Michael that this is a smell in the model design.
I don't think that can be made to work without changing the design. It's generally a bad idea in Java to have a design that requires you to access methods fields and properties through a name, and worse if the name is built from strings.
Possible solutions:
have getParts() return "resultA", "resultB", etc. and access them #{someOtherBean[getParts()]}
change the property names to a, b, c, d and access them as #{someOtherBean[getParts()]}
have a single property result that contains a Map with "A", "B", etc as keys and access the values as #{someOtherBean.result[getParts()]}
I have an object A which contains an object B. B has some fields. Is is possible, when serializing A to XML with XStream, to have all fields of B appear at the same level as fields of A?
More concretely, I have the following classes:
class B{
String foo = "bar";
}
class A{
B b;
}
I would like the output to look like:
<A>
<foo>bar</foo>
</A>
Instead of
<A>
<B>
<foo>bar</foo>
</B>
</A>
I have a question about outputing a list of objects as a comma separated list in JSF.
Let's say:
public class SomeObj {
private String name;
... constructors, getters and setters ...
}
and List<SomeObj>:
List<SomeObj> lst = new ArrayList<SomeObj>();
lst.add(new SomeObj("NameA"));
lst.add(new SomeObj("NameB"));
lst.add(new SomeObj("NameC"));
to output it as a listbox I can use this code:
<h:selectManyListbox id="id1"
value="#{listHolder.selectedList}">
<s:selectItems value="#{listHolder.lst}"
var="someObj"
label="#{someObj.name}"/>
<s:convertEntity />
</h:selectManyListbox>
But what is the easiest way to output the list as is, comma seperated ? Like this:
NameA, NameB, NameC
Should I use JSTL <c:forEach/> or may be the <s:selectItems/> tag can also be used ?
Given a List<Person> persons where Person has a name property,
If you're already on Java EE 7 with EL 3.0, then use EL stream API.
#{bean.persons.stream().map(p -> p.name).reduce((p1, p2) -> p1 += ', ' += p2).get()}
If you're not on EL 3.0 yet, but have JSF 2.x at hands, then use Facelets <ui:repeat>.
<ui:repeat value="#{bean.persons}" var="person" varStatus="loop">
#{person.name}#{not loop.last ? ', ' : ''}
</ui:repeat>
Or if you're still on jurassic JSP, use JSTL <c:forEach>.
<c:forEach items="#{bean.persons}" var="person" varStatus="loop">
${person.name}${not loop.last ? ', ' : ''}
</c:forEach>
See also:
How iterate over List<T> and render each item in JSF Facelets
JSTL in JSF2 Facelets... makes sense?
use <ui:repeat> (from facelets). It's similar to c:forEach
Or pre-compute the comma-separated string in the managed bean, and obtain it via a getter.
If you can't use varStatus because you're stuck with using JSF 1.2, you can do:
<ui:repeat value="#{listHolder.lst}" var="someObj">#{someObj != listHolder.lst[0] ? ',' : ''}
#{someObj.name}</ui:repeat>
The absence of whitespace around the EL-expressions is deliberate, we don't want a space to appear there in the rendered HTML.
I have a list of bean objects passed into my JSP page, and one of them is a comment field. This field may contain newlines, and I want to replace them with semicolons using JSTL, so that the field can be displayed in a text input. I have found one solution, but it's not very elegant. I'll post below as a possibility.
Here is a solution I found. It doesn't seem very elegant, though:
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<% pageContext.setAttribute("newLineChar", "\n"); %>
${fn:replace(item.comments, newLineChar, "; ")}
Just use fn:replace() function to replace \n by ;.
${fn:replace(data, '\n', ';')}
In case you're using Apache's EL implementation instead of Oracle's EL reference implementation (i.e. when you're using Tomcat, TomEE, JBoss, etc instead of GlassFish, Payara, WildFly, WebSphere, etc), then you need to re-escape the backslash.
${fn:replace(data, '\\n', ';')}
This is similar to the accepted answer (because it is using Java to represent the newline rather than EL) but here the <c:set/> element is used to set the attribute:
<c:set var="newline" value="<%= \"\n\" %>" />
${fn:replace(myAddress, newline, "<br />")}
The following snippet also works, but the second line of the <c:set/> element cannot be indented (and may look uglier):
<c:set var="newline" value="
" /><!--this line can't be indented -->
${fn:replace(myAddress, newline, "<br />")}
This solution is more elegant than your own solution which is setting the pagecontext attribute directly. You should use the <c:set> tag for this:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="newLine" value="\n"/>
${fn:replace(data, newLine, "; ")}
BTW: ${fn:replace(data, "\n", ";")} does NOT work.
This does not work for me:
<c:set var="newline" value="\n"/>
${fn:replace(data, newLine, "; ")}
This does:
<% pageContext.setAttribute("newLineChar", "\n"); %>
${fn:replace(item.comments, newLineChar, "; ")}
You could create your own JSP function.
http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSPTags6.html
This is roughly what you need to do.
Create a tag library descriptor file
/src/META-INF/sf.tld
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>sf</short-name>
<uri>http://www.stackoverflow.com</uri>
<function>
<name>clean</name>
<function-class>com.stackoverflow.web.tag.function.TagUtils</function-class>
<function-signature>
java.lang.String clean(java.lang.String)
</function-signature>
</function>
</taglib>
Create a Java class for the functions logic.
com.stackoverflow.web.tag.function.TagUtils
package com.stackoverflow.web.tag.function;
import javax.servlet.jsp.tagext.TagSupport;
public class TagUtils extends TagSupport {
public static String clean(String comment) {
return comment.replaceAll("\n", "; ");
}
}
In your JSP you can access your function in the following way.
<%# taglib prefix="sf" uri="http://www.stackoverflow.com"%>
${sf:clean(item.comments)}
If what you really need is a \n symbol you can use the advice from here:
${fn:replace(text, "
", "<br/>")}
or
<c:set var="nl" value="
" /><%-- this is a new line --%>
This includes the new line in your string literal.
You should be able to do it with fn:replace.
You will need to import the tag library into your JSP with the following declaration:
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
Then you can use the following expression to replace occurrences of newline in ${data} with a semicolon:
${fn:replace(data, "\n", ";")}
The documentation is not great on this stuff and I have not had the opportunity to test it.
\n does not represent the newline character in an EL expression.
The solution which sets a pageContext attribute to the newline character and then uses it with JSTL's fn:replace function does work.
However, I prefer to use the Jakarta String Tab Library to solve this problem:
<%# taglib prefix="str" uri="http://jakarta.apache.org/taglibs/string-1.1" %>
...
<str:replace var="result" replace="~n" with=";" newlineToken="~n">
Text containing newlines
</str:replace>
...
You can use whatever you want for the newlineToken; "~n" is unlikely to show up in the text I'm doing the replacement on, so it was a reasonable choice for me.
This is a valid solution for the JSP EL:
"${fn:split(string1, Character.valueOf(10))}"
More easily:
<str:replace var="your_Var_replaced" replace="\n" with="Your ney caracter" newlineToken="\n">${your_Var_to_replaced}</str:replace>
You could write your own JSP function to do the replacement.
This means you'd end up with something like:
<%# taglib prefix="ns" uri="..." %>
...
${ns:replace(data)}
Where ns is a namespace prefix you define and replace is your JSP function.
These functions are pretty easy to implement (they're just a static method) although I can't seem to find a good reference for writing these at the moment.
In the value while setting the var, press ENTER between the double quotes.
${fn:replace(data, newLineChar, ";")}
For the record, I came across this post while tackling this problem:
A multi-line string in JSTL gets added as the title attribute of a textarea. Javascript then adds this as the default text of the textarea. In order to clear this text on focus the value needs to equal the title... but fails as many text-editors put \r\n instead of \n. So the follownig will get rid of the unwanted \r:
<% pageContext.setAttribute("newLineChar", "\r"); %>
<c:set var="textAreaDefault" value="${fn:replace(textAreaDefault, newLineChar, '')}" />