JSF Chaining Converters [duplicate] - spring

I'm using JSF 2.
I have a method that checks for matching values from a list of values:
#ManagedBean(name="webUtilMB")
#ApplicationScoped
public class WebUtilManagedBean implements Serializable{ ...
public static boolean isValueIn(Integer value, Integer ... options){
if(value != null){
for(Integer option: options){
if(option.equals(value)){
return true;
}
}
}
return false;
}
...
}
To call this method in EL I tried:
#{webUtilMB.isValueIn(OtherBean.category.id, 2,3,5)}
But it gave me a:
SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-localhost/127.0.0.1:8080-5) java.lang.IllegalArgumentException: wrong number of arguments
Is there a way to execute such a method from EL?

No, it is not possible to use variable arguments in EL method expressions, let alone EL functions.
Your best bet is to create multiple different named methods with a different amount of fixed arguments.
public static boolean isValueIn2(Integer value, Integer option1, Integer option2) {}
public static boolean isValueIn3(Integer value, Integer option1, Integer option2, Integer option3) {}
public static boolean isValueIn4(Integer value, Integer option1, Integer option2, Integer option3, Integer option4) {}
// ...
As a dubious alternative, you could pass a commaseparated string and split it inside the method
#{webUtilMB.isValueIn(OtherBean.category.id, '2,3,5')}
or even a string array which is created by fn:split() on a commaseparated string
#{webUtilMB.isValueIn(OtherBean.category.id, fn:split('2,3,5', ','))}
but either way, you'd still need to parse them as integer, or to convert the passed-in integer to string.
In case you're already on EL 3.0, you could also use the new EL 3.0 collection syntax without the need for the whole EL function.
#{[2,3,5].contains(OtherBean.category.id)}

Related

Null Pointer Error when Mocking JDBC Template execute method [duplicate]

I've been trying to get to mock a method with vararg parameters using Mockito:
interface A {
B b(int x, int y, C... c);
}
A a = mock(A.class);
B b = mock(B.class);
when(a.b(anyInt(), anyInt(), any(C[].class))).thenReturn(b);
assertEquals(b, a.b(1, 2));
This doesn't work, however if I do this instead:
when(a.b(anyInt(), anyInt())).thenReturn(b);
assertEquals(b, a.b(1, 2));
This works, despite that I have completely omitted the varargs argument when stubbing the method.
Any clues?
Mockito 1.8.1 introduced anyVararg() matcher:
when(a.b(anyInt(), anyInt(), Matchers.<String>anyVararg())).thenReturn(b);
Also see history for this: https://code.google.com/archive/p/mockito/issues/62
Edit new syntax after deprecation:
when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);
A somewhat undocumented feature: If you want to develop a custom Matcher that matches vararg arguments you need to have it implement org.mockito.internal.matchers.VarargMatcher for it to work correctly. It's an empty marker interface, without which Mockito will not correctly compare arguments when invoking a method with varargs using your Matcher.
For example:
class MyVarargMatcher extends ArgumentMatcher<C[]> implements VarargMatcher {
#Override public boolean matches(Object varargArgument) {
return /* does it match? */ true;
}
}
when(a.b(anyInt(), anyInt(), argThat(new MyVarargMatcher()))).thenReturn(b);
Building on Eli Levine's answer here is a more generic solution:
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.mockito.ArgumentMatcher;
import org.mockito.internal.matchers.VarargMatcher;
import static org.mockito.Matchers.argThat;
public class VarArgMatcher<T> extends ArgumentMatcher<T[]> implements VarargMatcher {
public static <T> T[] varArgThat(Matcher<T[]> hamcrestMatcher) {
argThat(new VarArgMatcher(hamcrestMatcher));
return null;
}
private final Matcher<T[]> hamcrestMatcher;
private VarArgMatcher(Matcher<T[]> hamcrestMatcher) {
this.hamcrestMatcher = hamcrestMatcher;
}
#Override
public boolean matches(Object o) {
return hamcrestMatcher.matches(o);
}
#Override
public void describeTo(Description description) {
description.appendText("has varargs: ").appendDescriptionOf(hamcrestMatcher);
}
}
Then you can use it with hamcrest's array matchers thus:
verify(a).b(VarArgMatcher.varArgThat(
org.hamcrest.collection.IsArrayContaining.hasItemInArray("Test")));
(Obviously static imports will render this more readable.)
I have been using the code in Peter Westmacott's answer however with Mockito 2.2.15 you can now do the following:
verify(a).method(100L, arg1, arg2, arg3)
where arg1, arg2, arg3 are varargs.
I had to use the any(Class type) method to match an array arg being passed as a varargs parameter.
ArgumentMatchers.any(Class type)
Code in the implementation is vararg aware.
reportMatcher(new InstanceOf.VarArgAware(
In my case where matching a String[] arg to a String... param the following worked:-
any(String.class)
Building on topchef's answer,
For 2.0.31-beta I had to use Mockito.anyVararg instead of Matchers.anyVararrg:
when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);
Adapting the answer from #topchef,
Mockito.when(a.b(Mockito.anyInt(), Mockito.anyInt(), Mockito.any())).thenReturn(b);
Per the java docs for Mockito 2.23.4, Mockito.any() "Matches anything, including nulls and varargs."
You can accomplish this by passing an ArgumentCaptor capture and then retrieving the varargs as a list using "getAllValues", see: https://stackoverflow.com/a/55621731/11342928
As the other answers make sense and make tests work obviously, I still recommend to test as if the method didn't take a vararg, but rather regular well-defined parameters instead. This helps in situations where overridden methods in connection with possible ambiguous parameters are in place, like an SLF4J-logger:
to test:
jobLogger.info("{} finished: {} tasks processed with {} failures, took {}", jobName, count, errors, duration);
This has a bunch of overrides and the important method being declared like so
Logger.info(String, Object...)
verification:
verify(loggerMock).info(anyString(), anyString(), anyInt(), anyInt(), anyString());
proof that the above works as errors is an integer and not a long, so the following wouldn't run:
verify(loggerMock).info(anyString(), anyString(), anyInt(), anyLong(), anyString());
So you can easily use when() instead of the verify()-stuff to set up the required return value.
And it probably shows more of the intent and is more readable. Captures can also be used here and they are much easier accessible this way.
Tested with Mockito 2.15
In my case the signature of the method that I want to capture its argument is:
public byte[] write(byte ... data) throws IOException;
In this case you should cast to byte array explicitly:
when(spi.write((byte[])anyVararg())).thenReturn(someValue);
I'm using mockito version 1.10.19
You can also loop over the arguments:
Object[] args = invocation.getArguments();
for( int argNo = 0; argNo < args.length; ++argNo) {
// ... do something with args[argNo]
}
for example check their types and cast them appropriately, add to a list or whatever.

Use Method that returns an Int inside a Stream

I have a simple method :
public int getPrice(String bookingName)
{
//return the price of a booking
}
I also have the class :
public class Booking
{
String name;
...
}
I want to group the bookings in a map(key = name of the booking, value = getPrice(bookingName)) so I did :
public TreeMap<String, Integer> bookingForName() {
return bookings.stream().
collect(Collectors.groupingBy(Booking::getName,Collectors.summingInt(getPrice(Booking::getName))));
}
This doesnt' work it says :
Multiple markers at this line:
- The target type of this expression must be a functional interface
- The method getPrice(String) in the type Manager is not applicable for the arguments `(Booking::getName)`
How can I do?
Thanks!
Your getPrice() method takes a String, not a functional interface, so you can't call getPrice(Booking::getName), and even if you could, summingInt doesn't accept an int.
Change:
Collectors.summingInt(getPrice(Booking::getName))
to:
Collectors.summingInt(b -> getPrice(b.getName()))
Also note that Collectors.groupingBy returns a Map, not a TreeMap. If you must have a TreeMap, you should call a different variant of groupingBy.
public TreeMap<String, Integer> bookingForName() {
return bookings.stream()
.collect(Collectors.groupingBy(Booking::getName,
TreeMap::new,
Collectors.summingInt(b -> getPrice(b.getName()))));
}

Combining functions and consumers with double-column notation

I often use the double-colon notation for brevity.
I am writing the following method that takes a short list of entities, validates them, and saves back to database.
#Override#Transactional
public void bulkValidate(Collection<Entity> transactions)
{
Consumer<Entity> validator = entityValidator::validate;
validator = validator.andThen(getDao()::update);
if (transactions != null)
transactions.forEach(validator);
}
I'd like to know if there is a shorthand syntax avoiding to instantiate the validator variable
Following syntax is invalid ("The target type of this expression must be a functional interface")
transactions.forEach((entityValidator::validate).andThen(getDao()::update));
You could do that, but you would need to cast explicitly...
transactions.forEach(((Consumer<Entity>)(entityValidator::validate))
.andThen(getDao()::update));
The thing is that a method reference like this entityValidator::validate does not have a type, it's a poly expression and it depends on the context.
You could also define a method to combine these Consumers:
#SafeVarargs
private static <T> Consumer<T> combine(Consumer<T>... consumers) {
return Arrays.stream(consumers).reduce(s -> {}, Consumer::andThen);
}
And use it:
transactions.forEach(combine(entityValidator::validate, getDao()::update))

java 8 method reference to: either `equals` or `equalsIgnoreCase`

I tried to convert the body of a method boolean exists(String value, boolean isCaseSensitive) :
for(String str : existingNames){
if(isCaseSensitive ? str.equals(name) : str.equalsIgnoreCase(name)){
return true;
}
}
return false;
to a solution that utilises java8 method references:
Predicate<String> equalityPred = isCaseSensitive ?
name::equals :
name::equalsIgnoreCase;
return existingNames.stream().anyMatch(equalityPred);
Then I saw that this way the equality is performed in the opposite direction (e.g. value.equals(str) ).
Is there a way to fix this and still use method references, and if no what would be the java8 way.
There is no “opposite direction” for equality. The only issue might be the behavior for null values. Your loop might fail, if the collection contains null, your method references will fail, if name is null.
You may achieve the original behavior using lambda expressions:
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
Predicate<String> equalityPred = isCaseSensitive?
s -> s.equals(name):
s -> s.equalsIgnoreCase(name);
return existingNames.stream().anyMatch(equalityPred);
}
but it makes little sense to consider null for the name parameter, when it will never be equal, as the code will fail with a NullPointerException, if the collection contains null.
To get a sensible behavior for null, you may use
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
Predicate<String> equalityPred = name==null? Objects::isNull:
isCaseSensitive? name::equals: name::equalsIgnoreCase;
return existingNames.stream().anyMatch(equalityPred);
}
or just
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
return name==null || isCaseSensitive?
existingNames.contains(name):
existingNames.stream().anyMatch(name::equalsIgnoreCase);
}
If you know that the Collection will never contain null, but want to support null for the name parameter, you could also use
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
return name!=null && existingNames.stream()
.anyMatch(isCaseSensitive? name::equals: name::equalsIgnoreCase);
}
Well don't use a method reference then and write your lambda directly:
static boolean existsJDK8(List<String> existingNames, String value, boolean isCaseSensitive) {
Predicate<String> equalityPred = isCaseSensitive ? s -> value.equals(s) : s -> value.equalsIgnoreCase(s);
Predicate<String> equalityPredReversed = isCaseSensitive ? s -> s.equals(value) : s -> s.equalsIgnoreCase(value);
// return existingNames.stream().anyMatch(equalityPredReversed);
return existingNames.stream().anyMatch(equalityPred);
}

Validation Error: value is not valid when using a custom converter [duplicate]

This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 6 years ago.
NetBeans 7.1.1 JSF2.1
When using converter="convK" attribute in h:selectManyCheckBox it all works well. But I tried to use #FacesConverter(forClass=className.class) form and it keeps giving me "Validation is not Valid" errors. I've tried changing it to forClass=packageName.className.class but no help.
This is converter:
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
#FacesConverter( "convK")
public class KorisnikConverter implements Converter{
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value==null) return value;
if (value.isEmpty()) return value;
for (int i=0; i<Arhiva.getSviKor().size(); i++) {
if (Arhiva.getSviKor().get(i).getUsername().equals(value)) {
return Arhiva.getSviKor().get(i);
}
}
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value==null) return "";
if (value instanceof Korisnik) return ((Korisnik)value).getUsername();
return "";
}
}
I have a class called Korisnik which has couple text fields, username is unique one. In my main managing bean I have couple arrayList of those objects. Goal is to use selectManyCheckBox to chose just some of users and put them in a separate arraylist for some other uses. I wanted to push entire objects around (I can always easily work with strings and have object creation and management in my controler beans but wanted to try custom converters to get selectItems to work with objects)
In my class I've overridden equals and hashCode (as there is a lot of talk about custom converters giving blah blah Validation is not valid errors).
#Override
public boolean equals (Object obj) {
if (obj==null) return false;
if (!(obj instanceof Korisnik)) return false;
Korisnik k = (Korisnik)obj;
return (this.username==k.username);
}
#Override
public int hashCode() {
return this.username.hashCode();
}
Edit. When I'm using it as named converter and using said converter only in that one instance with selectManyCheckbox it works fine even without overriding equals and hashCode.
This is checkbox code
<h:selectManyCheckbox value="#{kontrolg.izabrAut}" layout="pageDirection" converter="convK" >
<f:selectItems value="#{kontrolg.moguciAut}" var="it" itemLabel="# {it.ime} #{it.prezime}" itemValue="#{it}"/>
</h:selectManyCheckbox>
What I don't know is whether I'm failing to properly use forClass="whatever" in converter annotation or my converter actually works ok with that one selectManyCheckbox, but when I specify it in forClass form it gets used for all instances of that object and causes some other code that worked nice before adding custom converters to now give "validation is not valid" error?
The value is not valid validation error will be thrown when the equals() method on the selected item has not returned true for any of the available items.
And indeed, your equals() method is broken. The following line is wrong:
return (this.username==k.username);
I'll assume that username is a String, which is an Object. The == compares Objects by reference, not by their value. In other words, when performing == on two Objects, you're basically testing if they point to exactly the same instance. You're not checking if they represent the same value (say, the Object instance's internal representation). You should be using the Object's equals() method instead, the String#equals() method, here's an extract of relevance from its javadoc:
equals
public boolean equals(Object anObject)
Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
The == is only applicable when comparing primitives like boolean, int, long, etc or when testing for null.
So, to fix your problem, replace the wrong line by the following line:
return username.equals(k.username);
Or, when they can possibly be null:
return (username == null) ? (k.username == null) : username.equals(k.username);
See also:
Right way to implement equals contract

Resources