Rethrowing exceptions at place of function/object construction - java

In the case of functions, when exceptions may only throw at their place of execution (based on my lack of knowledge this is uncertain for me at the moment), sometimes the culprit may rely on the way the lambda was created, an example may be:
// merge() will throw an exception if Function<S, Observable<T>> switchMap returns null.
public<S> void mergeSwitch(Observable<S> source, Function<S, Observable<T>> switchMap) {
final Mergeable<T> res = new Mergeable<>();
final Consumer<T> observer = creator(res, this); // Secondary subscription
setSource(
source, // Main subscription
new StateAwareObserver<S>() { // >>> implements Consumer<S>
Observable<T> switchRes = new Observable<>(); // Mediator
#Override
protected void onAdded() {
res.add(observer);
}
#Override
protected void onRemoved() {
res.remove(observer);
}
#Override
public void accept(S s) {
Observable<T> switchS = switchMap.apply(s);
if (switchRes != switchS) {
switchRes = switchS;
res.merge(switchS); //Where merge() throws if switchMap returns null
}
}
}
);
}
}
I've tried rethrowing the exception from the accept() method but it never gets pushed(pulled?) beyond its point of consumption, (where the consumer accepts "s"):
for (int i = observers.size() - 1; i >=0 ; i--) {
observers.get(i).accept(processed); // << -- StateAwareObserver<S> is stored in the *list*
}
-In this case I am using the word "beyond", but what I need is to throw the exception at its point of construction.-
In reality the real culprit may have been that the execution of the method: mergeSwitch(Observable<S> source, Function<S, Observable<T>> switchMap)
which created the Consumer<>, may have left something important out.
Or as is my case, the method executing mergeSwitch():
public<S> Forkable<S> forkSwitch(Function<T, Observable<S>> switchMap) {
Forkable<S> res = new Forkable<>();
res.mergeSwitch(this, switchMap);
return res;
}
In this case the issue was that the function was left with a null value.
public Holders.Forkable<List<Preset>> ledgerPresets = presetDao.forkSwitch(
presetDao -> ledgerId.forkSwitch(
aLong -> null
)
);
So if we take a look at the Consumer level, the real culprit would be:
#Override
public void accept(S s) {
int sVersion = source.getVersion();
if (sVersion != oVersion) {
Observable3<T> switchS = switchMap.apply(s); //< -- HERE
if (switchRes != switchS) {
switchRes = switchS;
res.merge(switchS);
}
oVersion = sVersion;
}
}
In this particular scenario, things can get out of hand easily since, the log may not stop at its nearest point of consumption, but the error may go all the way back to the root node.
Things can get even more complicated since the merge() method, which is the origin of the exception, may have been used from 3 different methods.
The ideal scenario would be that the exception would be thrown here:
public Holders.Forkable<List<Preset>> ledgerPresets = presetDao.forkSwitch(
presetDao -> ledgerId.forkSwitch( // <--- HERE
aLong -> null
)
);
But I haven't found a way to manage this particular exception rethrowing case yet.

EDIT:
In my previous answer I spent so much time trying to push the exception a stacktrace level, that I simply stopped trying to do it the easy way, you can ignore the craziness of the answer bellow the new one:
BEST ANSWER
public<S> Forkable<S> forkSwitch(Function<T, Observable<S>> switchMap) {
final IllegalStateException e = new IllegalStateException("switchMap must not be null");
final Forkable<S> res = new Forkable<>();
res.mergeSwitch(this,
t -> {
Observable<S> prev = switchMap.apply(t);
if (prev == null) {
throw e;
}
return prev;
}
);
return res;
}
OLD ANSWER
I tried searching for an answer but did not came up with an ideal one.
My solution has been capturing an int storing the top stacktrace and then infering the class name via the lambda.
public<S> Forkable2<S> forkSwitch(Function<T, Observable3<S>> switchMap) {
int lineNumber = Thread.currentThread().getStackTrace()[3].getLineNumber();
Forkable2<S> res = new Forkable2<>();
res.mergeSwitch(this,
t -> {
Observable3<S> prev = switchMap.apply(t);
if (prev == null) {
String lambdaS = switchMap.toString();
String prevLambdaS = lambdaS.substring(0, lambdaS.indexOf("$"));
throw new IllegalStateException("Switch map function must not return null!! at(" + prevLambdaS.substring(prevLambdaS.lastIndexOf(".") + 1) + ".java:"+ lineNumber + "), \n" +
"from: " + this);
}
return prev;
}
);
return res;
}
The reason why I find this solution to be lackluster is that the origin of the exception is actually not used, what we are really doing is intercepting the event before it actually happens, but imo this brings redundancy.
fortunately the exception is now more clear than before:
java.lang.IllegalStateException: Switch map function must not return
null!! at(PresetViewModel.java:66),
I believe one could encapsulate the entire process in a neat little object that creates the stacktrace before entering a lambda, and then creates an exception on command when required inside the lambda itself.
public<T, S> void toThrow(Function<T, S> throwableLambda) {
InferableThrow iT = new InferableThrow();
subscribe(
t -> {
S returned = throwableLambda.apply(t);
if (returned == null) {
throw iT.createExc(Class<? extends Exception>, Function<>, String message);
}
return returned;
}
);
}
Here is a helper object:
public final class InferableException<E extends RuntimeException> implements Supplier<E> {
private final Supplier<E> type;
public static<E extends RuntimeException> InferableException<E> create(
Function<String, E> type, Object lambdaObject, String message
) {
return new InferableException<>(type, lambdaObject, message);
}
private InferableException(Function<String, E> type, Object lambdaObject, String message) {
int lineNumber = Thread.currentThread().getStackTrace()[5].getLineNumber();
String lambdaS = lambdaObject.toString();
String prevLambdaS = lambdaS.substring(0, lambdaS.indexOf("$"));
String className = prevLambdaS.substring(prevLambdaS.lastIndexOf(".") + 1);
this.type = () -> type.apply(message +" at("+ className + ".java:" + lineNumber + ")");
}
#Override
public E get() {
return type.get();
}
}
Usage:
public<S> Forkable<S> forkSwitch(Function<T, Observable<S>> switchMap) {
final Supplier<IllegalStateException> e = InferableException.create( //<<-- construction
IllegalStateException::new,
switchMap,
"Switch map function must not return null!!"
);
Forkable<S> res = new Forkable<>();
res.mergeSwitch(this,
t -> {
Observable<S> prev = switchMap.apply(t);
if (prev == null) {
throw e.get(); //<<-- Throwing!!
}
return prev;
}
);
return res;
}

Related

java Mockito verify abstract method

i have an issue on verifying a call to method of class under test, using the verify() method it tells that the call is not done to that method, this method is defined as abstract in super class (loadFile(String))
find bellow the code :
public abstract class FileParser {
public Iterator<String> loadFile(FileSettingsToSend fileSetting) {
System.out.println("file before staged");
try {
if(!movFile("staged",fileSetting))
return null;
System.out.println("file after move "+fileSetting.getFile().getAbsolutePath());
boolean isValidFormatFile = fileValidator.checkFileFormat(fileSetting);
if (!isValidFormatFile) {
System.out.println("file format is not valid");
return null;
}
return readBlock(fileSetting);
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
} finally {
}
//return null;
}
public abstract Iterator<String> readBlock(FileSettingsToSend fileSettingsToSend)
throws JsonProcessingException, IOException;
}
public class JsonFileParser extends FileParser {
public final ObjectMapper mapper = new ObjectMapper();
#Autowired
public JsonFileParser(FileValidator jsonFileValidatorService, FileAttributeService fileAttributeService) {
super(jsonFileValidatorService, fileAttributeService);
}
#Override
public Iterator<String> readBlock(FileSettingsToSend fileSetting) throws JsonProcessingException, IOException {
ObjectMapper mapper = new ObjectMapper();
System.out.println("inside readBlock json implementation");
List<String> listAttribute = fileAttributeService.getAttributes(fileSetting.getDiretoryPath());
String[] blocDelimitor = fileAttributeService.getDelimitorRepositpry(fileSetting.getDiretoryPath());
System.out.println("after validator");
final JsonNode root = mapper.readTree(fileSetting.getFile());
if (root == null)
return null;
Iterator<JsonNode> nodeIterator = root.elements();
System.out.println("Data is " + root);
return new Iterator<String>() {
JsonNode node;
#Override
public boolean hasNext() {
return nodeIterator.hasNext();
}
#Override
public String next() {
int i = 0;
node = nodeIterator.next();
System.out.println("after nex " + node.toString());
Arrays.stream(blocDelimitor).forEach(e -> {
node = node.path(e);
System.out.println("inside next " + node.toString());
});
String result = null;
if (node.isArray()) {
System.out.println("It is Array");
for (JsonNode node1 : node) {
if (i != 0)
result = result + "," + listAttribute.stream().map(e -> e + "=" + node1.get(e))
.collect(Collectors.joining(","));
else
result = listAttribute.stream().map(e -> e + "=" + node1.get(e))
.collect(Collectors.joining(","));
i++;
}
} else
result = listAttribute.stream().map(e -> e + "=" + node.get(e)).collect(Collectors.joining(","));
return result;
}
};
}
Test method is :
#Mock
FileValidator jsonFileValidatorService;
#Mock
FileAttributeService fileAttributeService;
JsonFileParser jsonFileParserMock = new JsonFileParser(jsonFileValidatorService, fileAttributeService);
#Test
public void validatorNotTrue() throws JsonProcessingException, IOException{
when(jsonFileValidatorService.checkFileFormat( anyObject() )).thenReturn(true);
JsonFileParser jsonFileParser = Mockito.spy(jsonFileParserMock);
doReturn(true).when(jsonFileParser).movFile(anyString(),anyObject() );
assertNull(jsonFileParser.loadFile(null));
verify(jsonFileParser, times(1)).movFile(anyString(),anyObject());
assertTrue(jsonFileParser.movFile(anyString(), anyObject()));
assertTrue(jsonFileValidatorService.checkFileFormat( anyObject() ));
//exception.expect(Exception.class);
verify(jsonFileParser,times(1)).readBlock(anyObject();
}
#BeforeClass
public static void settingUp(){
}
#Before
public void initMock(){
MockitoAnnotations.initMocks(this);
}
the line verify(jsonFileParser,times(1)).readBlock(anyObject(); return false; meaning that the method loadFile of jsonfileParser not called
can you get your held to tell why it is not called.
Thank you.
This happens because you initialize the mocks after you create a JsonFileParser. Note that #Before method is executed after all the fields of your test class are initialized.
As a result, you pass null dependencies to the class. The invocation to the null FileValidator throws NullPointerException, but you swallow it in your catch block.
Generally it is advisable to verify the arguments you pass to your constructors and methods, to fail fast in case of an error. For example, Java comes with a handy Objects::requireNonNull method to verify that the passed parameters are non-null.
Similarly it's generally a bad practice to swallow every single exception. For instance, in your example, you expect IOException and JsonProcessingException to be thrown. It's better to catch these explicitly and let the program crash (or at least log a warning) for any other one.
Finally, mocks and spies are prone to overuse. Usually, it's enough to use fakes - dummy implementations of your interfaces. Depending on how much control you have over the code, you may also want to refactor it to avoid using a spy at all. Using one in a code you may freely change may signal an architectural problem.

Bean post processor for Retry annotation

I have a legacy project with Spring version 3.0 (I can't use Retriable annotation from spring package).
I want to implement Retryable annotation to annotate my methods which execution should be retry on fail.
This is my class:
#Component
public final class RetryBpp implements BeanPostProcessor {
private final ConcurrentMap<String, ClassDefinition> map = new ConcurrentHashMap<>();
#Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
final Class<?> asClass = bean.getClass();
final Method[] methods = asClass.getMethods();
final List<Method> collect = Stream.of(methods)
.filter(method -> method.isAnnotationPresent(Repitable.class))
.collect(Collectors.toList());
if(!collect.isEmpty()){
this.map.put(beanName,new ClassDefinition(collect,asClass));
}
return bean;
}
#Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
final ClassDefinition definition = this.map.get(beanName);
if(definition != null){
final Class beanClass = definition.asClass;
return Proxy.newProxyInstance(beanClass.getClassLoader(), beanClass.getInterfaces(), (proxy, method, args) -> {
if(definition.isMethodPresent(method)){
System.out.println("Present");
return this.retry(definition.originalMethod(method),bean,args);
} else{
return method.invoke(bean,args);
}
});
} else{
return bean;
}
}
private Object retry(final Method method,final Object originalBean,Object[] argc){
final Repitable repitable = method.getAnnotation(Repitable.class);
int attempts = repitable.attempts();
Throwable exc = null;
while(attempts!=0){
try{
return method.invoke(originalBean,argc);
}catch (final Throwable throwable){
exc = throwable;
attempts--;
this.sleep(repitable.delay(),repitable.timeUnit());
}
}
throw new RuntimeException(exc);
}
#SneakyThrows(InterruptedException.class)
private void sleep(final int time, final TimeUnit timeUnit){
timeUnit.sleep(time);
}
#AllArgsConstructor
private static final class ClassDefinition{
private final List<Method> methods;
private final Class asClass;
boolean isMethodPresent(final Method method){
return this.methods.stream().anyMatch(mthd->mthd.getName().equals(method.getName()));
}
Method originalMethod(final Method method){
return this.methods.stream().filter(mthd->mthd.getName().equals(method.getName())).findFirst().orElseThrow(NullPointerException::new);
}
}
}
And it work but I want to change two things
1)In retry method I want to keep last exception and throw when repeateCount = 0 for this I need to declare null ptr to exc, but I want all my fields to be final. Is it any possible way to rewrite my code?
2) In ClassDefinition I compare Method by name because original equals method of Method class compare by class, I can't do it because original class replaced by proxy, Is it possible to compare two Method's in different way?
For the first part: one option is to use a List of the Throwables. And then throw them something like:
final RuntimeException theError = new RuntimeException(list.get(list.size() - 1));
for (int i = 0; i < list.size() - 1; i++) {
theError.addSuppressed(list.get(i));
}
throw theError;
This also gives the benefit of providing all the failures.
For the latter part, this could be complicated and expensive depending on whether there's gonna be generics, var-args, etc. on some of the methods.
Since you're already using spring, you could try a combination of: AopUtils.getTargetClass and AopUtils.getMostSpecificMethod to get what you want (would need to refactor what you pass to some of the test methods).
Something simple to provide some more (note, not infallible) tests in the vein of what you're already running with though:
return methods.stream().anyMatch(mthd -> {
if (!method.getName().equals(mthd.getName())) {
return false;
}
if (!method.getReturnType().isAssignableFrom(mthd.getReturnType())) {
return false;
}
final Class<?>[] parameterTypes = method.getParameterTypes();
if (mthd.getParameterTypes().length != parameterTypes.length) {
return false;
}
for (int i = 0; i < parameterTypes.length; i++) {
if (!parameterTypes[i].equals(mthd.getParameterTypes()[i])) {
return false;
}
}
return true;
});
I'm sure there are some more checks you can do (Method.getExceptionTypes() to confirm they could override; Method.getDeclaringClass() and work up the tree from there; Method.getModifiers() to determine if it could be overridden, etc.), but that depends on how safe you need to be.

Is there a nicer (java8?) way to collect the "cause stack" of an exception?

We have a BaseException extends Exception in our project, and basically all our other exceptions derive from this class. I want to change some methods that deal with the "cause stack" at runtime.
As starting point, I wrote the following method:
class BaseException extends Exception {
...
/**
* Helper: creates a list containing the complete "cause stack" of this exception.
* Please note: the exception on which this method is called is part of result!
*
* #return a {#link List} of all "causes" of this exception
*/
List<Throwable> getAllCauses() {
Throwable cause = this;
List<Throwable> causes = new ArrayList<>();
while (cause != null) {
causes.add(cause);
cause = cause.getCause();
}
return causes;
}
This gets the job done, although it is not perfect (name isn't exactly great, and single layer of abstraction is violated, too) .
But still: is there a "more elegant" way of collecting this result? Especially given the fact that it would helpful to directly return a Stream<Throwable>.
( I am mainly wondering if there is a java8 lambda/idiom that could help here )
This article should be of help. In particular,
Stream<Throwable> causes(Throwable t){
if (t == null) return Stream.empty();
return Stream.concat(Stream.of(t), causes(t.getCause()));
}
Here is my implementation that implemented by Spliterator as below:
public static <T> Stream<T>
iterateUntil(T seed, UnaryOperator<T> generator, Predicate<T> proceed){
return stream(new AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED){
private T value = seed;
public boolean tryAdvance(Consumer<? super T> action){
if(!proceed.test(value)) return false;
action.accept(value);
value = generator.apply(value);
return true;
}
}, false);
}
Then you can implements your getCauses as below and it drop the recursive calls:
List<Throwable> getAllCauses() {
return iterateUntil(this, Throwable::getCause, Objects::nonNull)
.collect(toList());
}
Using some enumeration seems more appropriate to me, then something like
class BaseException extends Exception {
...
Enumeration<Throwable> getCauses() {
return new Enumeration<Throwable>() {
private Throwable current = BaseException.this;
public boolean hasMoreElements() {
return current != null;
}
public Throwable nextElement() {
Throwable c = current;
current = current.getCause();
return c;
}
}
}
With Java 8 you can also create a new interface with a default method doing the trick and then use that interface in any of your exception class (slightly better than subclassing Exception?).

Multiple #QueryParam keys for a single value in Jersey

Is it possible to allow multiple #QueryParam keys for a single object/variable in Jersey?
Actual:
#POST
public Something getThings(#QueryParam("customer-number") Integer n) {
...
}
so, if I add ?customer-number=3 after the URL it works.
Expected:
I want to get the behavior above if I add any of the following values:
?customer-number=3
?customerNumber=3
?customerNo=3
Obs:
The QueryParam annotation looks like:
...
public #interface QueryParam {
String value();
}
so, it cannot accept multiple String values (like #Produces).
The approach below allows the user to use multiple keys having the same meaning at the same time (and I want to have an "OR" condition between them):
#POST
public Something getThings(#QueryParam("customer-number") Integer n1,
#QueryParam("customerNumber") Integer n2,
#QueryParam("customerNo") Integer n3) {
...
}
Something like this doesn't work:
#POST
public Something getThings(#QueryParam("customer-number|customerNumber|customerNo") Integer n) {
...
}
How can I do this?
Details:
Jersey 2.22.1
Java 8
To be honest: this is not how webservices are supposed to be designed. You lay down a strict contract that both client and server follow; you define one parameter and that's it.
But of course it would be a perfect world where you have the freedom to dictate what is going to happen. So if you must allow three parameters in, then you'll have to make that the contract. This is one way following approach #2 which I have to provide without being able to test it for goofs:
public Something getThings(#QueryParam("customer-number") Integer n1,
#QueryParam("customerNumber") Integer n2,
#QueryParam("customerNo") Integer n3) throws YourFailureException {
Integer customerNumber = getNonNullValue("Customer number", n1, n2, n3);
// things with stuff
}
private static Integer getNonNullValue(String label, Integer... params) throws YourFailureException {
Integer value = null;
for(Integer choice : params){
if(choice != null){
if(value != null){
// this means there are at least two query parameters passed with a value
throw new YourFailureException("Ambiguous " + label + " parameters");
}
value = choice;
}
}
if(value == null){
throw new YourFailureException("Missing " + label + " parameter");
}
return value;
}
So basically reject any call that does not pass specifically one of the parameters, and let an exception mapper translate the exception you throw into a HTTP response code in the 4xx range of course.
(I made the getNonNullValue() method static is it strikes me as a reusable utility function).
Maybe the simplest and easiest way would be to use a custom #BeanParam:
First define the custom bean merging all the query parameters as:
class MergedIntegerValue {
private final Integer value;
public MergedIntegerValue(
#QueryParam("n1") Integer n1,
#QueryParam("n2") Integer n2,
#QueryParam("n3") Integer n3) {
this.value = n1 != null ? n1
: n2 != null ? n2
: n3 != null ? n3
: null;
// Throw an exception if value == null ?
}
public Integer getValue() {
return value;
}
}
and then use it with #BeanParam in your resource method:
public Something getThings(
#BeanParam MergedIntegerValue n) {
// Use n.getValue() ...
}
Reference: https://jersey.java.net/documentation/latest/user-guide.html#d0e2403
You can create a custom annotation. I won't go in too much about how to do it, you can see this post, or this post. Basically it relies on a different infrastructure than the usual dependency injection with Jersey. You can see this package from the Jersey project. This is where all the injection providers live that handle the #XxxParam injections. If you examine the source code, you will see the the implementations are fairly the same. The two links I provided above follow the same pattern, as well as the code below.
What I did was created a custom annotation
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface VaryingParam {
String value();
#SuppressWarnings("AnnotationAsSuperInterface")
public static class Factory
extends AnnotationLiteral<VaryingParam> implements VaryingParam {
private final String value;
public static VaryingParam create(final String newValue) {
return new Factory(newValue);
}
public Factory(String newValue) {
this.value = newValue;
}
#Override
public String value() {
return this.value;
}
}
}
It may seem odd that I have a factory to create it, but this was required for the implementation of the below code, where I split the value of the String, and end up creating a new annotation instance for each split value.
Here is the ValueFactoryProvider (which, if you've read either of the above articles, you will see that is required for custom method parameter injection). It a large class, only because I put all the required classes into a single class, following the pattern you see in the Jersey project.
public class VaryingParamValueFactoryProvider extends AbstractValueFactoryProvider {
#Inject
public VaryingParamValueFactoryProvider(
final MultivaluedParameterExtractorProvider mpep,
final ServiceLocator locator) {
super(mpep, locator, Parameter.Source.UNKNOWN);
}
#Override
protected Factory<?> createValueFactory(final Parameter parameter) {
VaryingParam annotation = parameter.getAnnotation(VaryingParam.class);
if (annotation == null) {
return null;
}
String value = annotation.value();
if (value == null || value.length() == 0) {
return null;
}
String[] variations = value.split("\\s*\\|\\s*");
return new VaryingParamFactory(variations, parameter);
}
private static Parameter cloneParameter(final Parameter original, final String value) {
Annotation[] annotations = changeVaryingParam(original.getAnnotations(), value);
Parameter clone = Parameter.create(
original.getRawType(),
original.getRawType(),
true,
original.getRawType(),
original.getRawType(),
annotations);
return clone;
}
private static Annotation[] changeVaryingParam(final Annotation[] annos, final String value) {
for (int i = 0; i < annos.length; i++) {
if (annos[i] instanceof VaryingParam) {
annos[i] = VaryingParam.Factory.create(value);
break;
}
}
return annos;
}
private class VaryingParamFactory extends AbstractContainerRequestValueFactory<Object> {
private final String[] variations;
private final Parameter parameter;
private final boolean decode;
private final Class<?> paramType;
private final boolean isList;
private final boolean isSet;
VaryingParamFactory(final String[] variations, final Parameter parameter) {
this.variations = variations;
this.parameter = parameter;
this.decode = !parameter.isEncoded();
this.paramType = parameter.getRawType();
this.isList = paramType == List.class;
this.isSet = paramType == Set.class;
}
#Override
public Object provide() {
MultivaluedParameterExtractor<?> e = null;
try {
Object value = null;
MultivaluedMap<String, String> params
= getContainerRequest().getUriInfo().getQueryParameters(decode);
for (String variant : variations) {
e = get(cloneParameter(parameter, variant));
if (e == null) {
return null;
}
if (isList) {
List list = (List<?>) e.extract(params);
if (value == null) {
value = new ArrayList();
}
((List<?>) value).addAll(list);
} else if (isSet) {
Set set = (Set<?>) e.extract(params);
if (value == null) {
value = new HashSet();
}
((Set<?>) value).addAll(set);
} else {
value = e.extract(params);
if (value != null) {
return value;
}
}
}
return value;
} catch (ExtractorException ex) {
if (e == null) {
throw new ParamException.QueryParamException(ex.getCause(),
parameter.getSourceName(), parameter.getDefaultValue());
} else {
throw new ParamException.QueryParamException(ex.getCause(),
e.getName(), e.getDefaultValueString());
}
}
}
}
private static class Resolver extends ParamInjectionResolver<VaryingParam> {
public Resolver() {
super(VaryingParamValueFactoryProvider.class);
}
}
public static class Binder extends AbstractBinder {
#Override
protected void configure() {
bind(VaryingParamValueFactoryProvider.class)
.to(ValueFactoryProvider.class)
.in(Singleton.class);
bind(VaryingParamValueFactoryProvider.Resolver.class)
.to(new TypeLiteral<InjectionResolver<VaryingParam>>() {
})
.in(Singleton.class);
}
}
}
You will need to register this class' Binder (bottom of class) with Jersey to use it.
What differentiates this class from Jersey QueryParamValueFactoryProvider is that instead of just processing a single String value of the annotation, it splits the value, and tries to extract the values from the query param map. The first value found will be returned. If the parameter is a List or Set, it just continues to keep looking up all the options, and adding them to the list.
For the most part this keeps all the functionality you would expect from an #XxxParam annotation. The only thing that was difficult to implement (so I left out supporting this use case), is multiple parameters, e.g.
#GET
#Path("multiple")
public String getMultipleVariants(#VaryingParam("param-1|param-2|param-3") String value1,
#VaryingParam("param-1|param-2|param-3") String value2) {
return value1 + ":" + value2;
}
I actually don't think it should be that hard to implement, if you really need it, it's just a matter of creating a new MultivaluedMap, removing a value if it is found. This would be implemented in the provide() method of the VaryingParamFactory above. If you need this use case, you could just use a List or Set instead.
See this GitHub Gist (it's rather long) for a complete test case, using Jersey Test Framework. You can see all the use cases I tested in the QueryTestResource, and where I register the Binder with the ResourceConfig in the test configure() method.

Java: boolean primitive private method returning false even though set to true

I have a public method which calls a private method, which conditionally calls another private method. All three methods return a boolean primitive value, however the value is sometimes changing from what I expect it to be.
I am certain I am missing something incredibly obvious, but I am now too close to the code to see the problem.
Here is a cleaned up sample version of the code and the results I am seeing:
EDIT: I have added the ACTUAL code at the bottom
public class MyClass {
// Default Constructor
public MyClass() {}
public boolean foo(final Object arg0, final Object arg1, final Object arg2) {
final boolean result = this.bar(arg0, arg1, arg2);
System.out.println("foo: " + result);
return result;
}
private boolean bar(final Object arg0, final Object arg1, final Object arg2) {
boolean result = false;
System.out.println("bar: " + result);
try {
// complicated code that could generate an exception
if (this.wowsers(arg0, arg1, arg2)) {
result = true;
System.out.println("bar: " + result);
System.out.println("bar: call to wowsers() returned true");
}
} catch (Exception e) {
System.out.println("SOMETHING BLEW UP");
e.printStackTrace();
} finally {
// This should NOT change result
this.irrelevantMethod_1(null);
this.irrelevantMethod_2(null);
this.irrelevantMethod_3(null);
}
System.out.println("bar: " + result);
return result;
}
private boolean wowsers(final Object arg0, final Object arg1, final Object arg2) {
boolean result = false;
// complicated code involving the passed in arguments
// this MIGHT change result
System.out.println("wowsers: " + result);
return result;
}
private void irrelevantMethod_1(Object arg0) {
// Nothing in here to change result
}
private void irrelevantMethod_2(Object arg0) {
// Nothing in here to change result
}
private void irrelevantMethod_3(Object arg0) {
// Nothing in here to change result
}
} // END Class MyClass
Calling Code:
MyClass myInstance = new MyClass();
myInstance.foo();
Console Output:
> bar: false
> wowsers: true
> bar: true
> bar: call to wowsers() returned true
> foo: false
In the sample above, the value of result gets set to true in method dowsers(), and is correctly returned to bar(). When bar() tests the returned value from wowsers() and finds it to be true it sets it's own result to true and prints to the console the value of result and prints that dowsers() returned a true.
The System.out.println at the end of bar() is NEVER executed (at least I never see anything show up in the console), and the value of result (which at this point is true) is returned as false.
The foo() method then prints the value it received from the call to bar, which is always false.
Does anybody see where I'm messing up?
EDIT: Here is the ACTUAL code -replaces methods foo() and bar()
public boolean sendReminderNotifcation(final RequestController controller, final Session session, final Request request,
final Comment comment, final boolean treatAsNewNote) {
final boolean result = this.sendNotification(controller, session, request, comment, null, MailType.Remind, treatAsNewNote);
System.out.println("sendReminderNotifcation(): " + result);
System.out.println("***");
return result;
}
private boolean sendNotification(final RequestController controller, final Session session, final Request request,
final Comment comment, final TreeSet<String> copyto, final MailType mailtype, final boolean treatAsNewNote) {
HashMap<NotifyWhom, TreeSet<String>> sendTo = null;
boolean result = false;
System.out.println("sendNotification(): " + result);
try {
if (null == controller) { throw new IllegalArgumentException("RequestContoller is null"); }
this.setRequestURLprefix(controller.getRequestURLprefix());
if (null == session) { throw new IllegalArgumentException("Session is null"); }
if (null == request) { throw new IllegalArgumentException("Request is null"); }
if (null == mailtype) { throw new IllegalArgumentException("mailtype is null"); }
final EnumSet<NotifyWhom> recipients = this.getRecipients(controller, session, request, mailtype, treatAsNewNote);
if ((null == recipients) || recipients.isEmpty()) { return false; }
final HashMap<NotifyWhom, TreeSet<String>> tempSendTo = this.getSendTo(controller, request, recipients);
if (null == tempSendTo) { throw new RuntimeException("NO RECIPIENTS FOR NOTIFICATION"); }
// clear out any duplicates
sendTo = this.purgeDuplicateRecpients(tempSendTo);
// Update Prior Assignee Information
// Update Requestor Information
// Update Queue Owner Information
this.updateReOpenedInformation(controller, session, request);
final String subject = (request.isReOpened()) ? HelpdeskNotifications.SUBJECT_REOPENED : HelpdeskNotifications.SUBJECT_UPDATED;
final Iterator<Entry<NotifyWhom, TreeSet<String>>> sit = sendTo.entrySet().iterator();
final TreeSet<NameHandle> exclude = this.getExcludeRecipients();
while (sit.hasNext()) {
final Map.Entry<NotifyWhom, TreeSet<String>> entry = sit.next();
final MailNotifyKey key = new MailNotifyKey(this.getLogger(), mailtype, entry.getKey());
if (MailType.Remind.equals(mailtype)) {
final Status status = request.getStatus();
final MailRecipientOption mro = (null == status) ? null : status.getMailRecipientOption(key);
// A null mro indicates that Notifications are DISABLED
if (null == mro) { return false; }
}
final TreeSet<String> sendto = entry.getValue();
if (this.sendEmail(controller, session, request, subject, comment, sendto, copyto, exclude, key, treatAsNewNote)) {
result = true;
System.out.println("sendNotification(): " + result);
System.out.println("sendNotification(): (call to sendEmail() returned true)");
}
}
// Send Special Re-Opened Notifications
if (this.sendReOpenedNotifications(controller, session, request, subject, comment, treatAsNewNote)) {
result = true;
System.out.println("sendNotification(): " + result);
System.out.println("sendNotification(): (call to sendReOpenedNotifications() returned true)");
}
} catch (final Exception e) {
this.getLogger().logException(this, e);
e.printStackTrace();
} finally {
this.setPriorAssigneeNotify(null);
this.setReOpenedRecipients(null);
this.setExcludeRecipients(null);
}
System.out.println("sendNotification(): " + result);
return result;
}
The Console Output I am getting is:
> sendNotification(): false
> sendNotification(): true
> sendNotification(): (call to sendEmail() returned true)
> sendReminderNotifcation(): false
> ***
(I realize I should have posted the ACTUAL code in the first place)
For some reason I cannot figure out, it seems as though the final two lines of code in method bar() and method sendNotification() do not appear to be running. Is there some other way for a method to complete and return that I am unaware of?
I suggest you put a debug print statement before this line:
if (null == mro) { return false; }
Since this is in a while loop, and allows the method to return false even thoughresult has been set true. I'll bet this is where the false return is coming from, and why you don't see the final print statements being executed.
Read this :
Is Java "pass-by-reference" or "pass-by-value"?
In this method
private boolean wowsers(final Object arg0, final Object arg1, final Object arg2) {
boolean result = false;
// complicated code involving the passed in arguments
// this MIGHT change result
System.out.println("wowsers: " + result);
return result;
}
You re-instantiate boolean varaible. This is a new boolean result outside of scope method bar
Simply block. Just think.
result = true;
System.out.println("bar: " + result);
And finally it looks like a
private boolean bar(final Object arg0, final Object arg1, final Object arg2) {
boolean result = false;
// no reassignee result value
return result;
}
so you return false
final boolean result
This means you want result will never change after its first value.
And that's what you get.
Remove final.

Categories