I am trying to implement retry attempts functionality while handling exception using spring-retry. I am using #Retryable as described in my code sample below. But I am facing a strange issue here.
When I use this annotation, it does retry for 3 times which is default, but it does not throw the custom exception, i.e. MyGraphDBServiceException which I have made for my application. Instead, it throws the ArrayIndexOutOfBoundException. When I remove that annotation form the method, I get MyGraphDBServiceException as expected.
How can I ensure that MyGraphDBServiceException gets thrown even when I am using this annotation?
#Override
#Retryable(value = {MyGraphDBServiceException.class, MyGraphDBRedisServiceException.class}, backoff = #Backoff(delay = 1000))
public Long beginTransaction() {
//TODO: provide custom exception handling here
if (configs.isEmpty())
throw new MyGraphDBServiceException(SERVICE_UNAVAILABLE_EXCEPTION);
Long txnId = null;
List<TransactionObject> txnList = new LinkedList<>();
try {
//should throw exception here which should be MyGraphDBServiceException
txnId = txnList.get(0).getTransactionId();
Gson gson = new Gson();
String txnString = gson.toJson(txnList);
redisServiceUtility.add(String.valueOf(txnId), txnString);
} catch (Exception e) {
//TODO: provide custom exception handling here
log.error("[Exception] Caught in redis: {}", e.getMessage());
throw new MyGraphDBServiceException(SERVICE_UNAVAILABLE_EXCEPTION);
}
return txnId;
}
just to be clear, I do get MyGrpahDBServiceException when I run the same code but without #Retryable annotation. So please don't think that my code should throw ArrayIndexOutOfBoundException rather than custom one.
Related
We have the following snippet of code in Spring-Boot:
#Value("${service.image.cloud.host}")
String imgUrl;
private final ImageValidationProperties imageValidationProperties;
public ImageResponse getImageslistFromCloud(String image, Integer cloud) {
String imageNumber = "0RC";
String url = imgUrl;
if (cloud != null) {
imageNumber = imageValidationProperties.getImagesFromCloud(cloud);
url = imageValidationProperties.getUrlFromCloud(cloud);
}
log.debug("Request images", imageNumber);
ResponseEntity<ImageResponse> imgResponse = null;
try {
RestTemplate template = new RestTemplate();
imgResponse = template.getForEntity(url.concat(imageNumber).concat(imgUrl), ImageResponse.class);
return imgResponse.getBody();
}
catch (Exception e) {
log.error("error: {}", e);
return imgResponse.getBody();
}
}
My supervisor told me that it could throw a Null Pointer Exception which is not handled, but I dont understand how it could be fixed. I have used try and catch already so I am not sure what could go wrong.
Someone has idea what could be wrong? I apperciate any help :)
#Value property is null because your Class doesn't have a Bean, try to annotate your class with #Service, #Component or even use a #Bean annotation.
Your catch block will throw a NullPointerException if template.getForEntity resulted in an HTTP error (e.g. if the resource could not be found). In this case imgResponse is still null and you call the getBody() method on it. Instead you should return null or use Optional as return type and return Optional.empty().
You should also avoid to catch the very common Exception and be more specific about the exceptions you want to catch.
In try block you instantiated imgResponse field.But, In catch block you directly returned response by using imgResponse.getBody(); statement. Which will possibly throw NullPointerException.
One best way to avoid NullPointerException is to use java.util.Optional. Which could potential save to break your code at runtime.
I think the problem is with imgResponse.getBody() in the catch block. imgResponse is still null in the catch block, which will throw NPE when imgResponse.getBody() is called.
Another place is: you need to initialize the variable imageValidationProperties as well, otherwise its method call will result in null pointer exception
(imageNumber = imageValidationProperties.getImagesFromCloud(cloud);
url = imageValidationProperties.getUrlFromCloud(cloud);)
For below method, is there a way to create unit test to cause DatatypeConfigurationException, so I can test that it threw ConversionException?
Here is my code:
public static XMLGregorianCalendar getXMLGregorianCalendar(final LocalDate localDate) {
XMLGregorianCalendar xmlGregorianCalendar = null;
if (localDate != null) {
final String dateString = localDate.format(yyyMMddFormat);
try {
xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(dateString);
} catch (DatatypeConfigurationException e) {
throw new ConversionException("Unable to format LocalDate.", e);
}
}
return xmlGregorianCalendar;
}
You can override the implementation that the factory will create by setting a system property with a classname to instantiate. Then that class can throw an exception in that method.
For example like this
public class FailingDatatypeFactory implements DatatypeFactory {
public XMLGregorianCalendar newXMLGregorianCalendar() { throw new DatatypeConfigurationException() }
}
and then set it up like so
System.setProperty("javax.xml.datatype.DatatypeFactory", FailingDatatypeFactory.class.getName());
Now after you run your test case you should clear the property so no other tests try to instantiate that implementation.
I just had to do this for my unit tests. All you need to do is set the Sys prop javax.xml.datatype.DatatypeFactory to something invalid. It will throw the exception when it tries to find the class that doesn't exist. Just be sure to clear the prop after your test.
Here the checked exception is thrown by javax.xml.datatype.DatatypeFactory.newInstance().
It is a static method. So you cannot mock it straightly.
1) As alternative you could try to find the scenario that could provoke the exception to be risen.
Let's go. The exception is throw here :
private static <T> T findServiceProvider(final Class<T> type)
throws DatatypeConfigurationException{
try {
return AccessController.doPrivileged(new PrivilegedAction<T>() {
public T run() {
final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
final Iterator<T> iterator = serviceLoader.iterator();
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
});
} catch(ServiceConfigurationError e) {
final DatatypeConfigurationException error =
new DatatypeConfigurationException(
"Provider for " + type + " cannot be found", e);
throw error;
}
}
So DatatypeConfigurationException is thrown when ServiceConfigurationError is thrown and caught. But ServiceConfigurationError is an error and not an exception.
Trying to simulate an error becomes very hacky.
2) Other alternative to test it : wrapping DatatypeFactory.newInstance() in an instance of your own class.
In this way you can mock it without difficulty :
public class DataTypeFactoryWrapper {
public DatatypeFactory newInstance(){
return DatatypeFactory.newInstance();
}
}
Now change your code in this way :
private DataTypeFactoryWrapper dataTypeFactoryWrapper;
//...
xmlGregorianCalendar = dataTypeFactoryWrapper.newInstance().newXMLGregorianCalendar(dateString);
Now you can mock dataTypeFactoryWrapper in your test class.
3) Last alternative : don't test it. Consider it as it is, that is an Error wrapper and Error are hard/tricky to test.
Whatever the javadoc explains that :
An Error is a subclass of Throwable that indicates serious problems
that a reasonable application should not try to catch. Most such
errors are abnormal conditions
You can either:
Mock static method (DatatypeFactory.newInstance()) using PowerMock for example and set it up to throw DatatypeConfigurationException. Then in unit test check that this exception is wrapped by ConversionException.
Since I'm not a big fan of mocking static methods - I would create new component - say XmlGregorianCalendarProvider (which will use DatatypeFactory.newInstance().newXMLGregorianCalendar(dateString) internally) and mock it instead using standard mocking mechanism (e.g. JUnit).
Still then in unit test check that this exception is wrapped by ConversionException.
I'm trying to get the same result as when I use #Valid in object parameter from a Controller. When the object is invalid an exception (MethodArgumentNotValidException) is throw by my ExceptionHandlerController who has #RestControllerAdvice.
In my case I want to validate an object, but I only can validate it in service layer. The object have bean validation annotations, so I'm trying to programmatically throw MethodArgumentNotValidException for my ExceptionHandlerController handle it, but I'm not having success.
So far I have this:
private void verifyCard(CardRequest card) {
BeanPropertyBindingResult result = new BeanPropertyBindingResult(card, "card");
SpringValidatorAdapter adapter = new SpringValidatorAdapter(this.validator);
adapter.validate(card, result);
if (result.hasErrors()) {
try {
throw new MethodArgumentNotValidException(null, result);
} catch (MethodArgumentNotValidException e) {
e.printStackTrace();
}
}
}
The first parameter is from type MethodParameter and I'm not been able to create this object. Is it the best way to handle my problem?
EDIT 1:
I can't remove the try/catch block. When I remove it I get compile error. How to work around?
You have already handled it by the catch block, you should remove try-catch to your global handler catch it.
then specify the method like below
private void verifyCard(CardRequest card) throws MethodArgumentNotValidException
MethodArgumentNotValidException is a subclass of Exception. This means that it's "checked": To throw it out of your verifyCard(..) method, you have to declare that verifyCard(..) can throw it:
private void verifyCard(CardRequest card) throws MethodArgumentNotValidException {
// your code
}
If you have lombok dependency in your project, you can also fake compiler by using #SneakyThrows annotation.
https://projectlombok.org/features/SneakyThrows
throw new MethodArgumentNotValidException(null, result);
Above constructor will not work as method parameter is necessary.
Valid constructor (reference) is:
MethodArgumentNotValidException(MethodParameter parameter, BindingResult bindingResult);
Hence, in your case:
throw new MethodArgumentNotValidException(new MethodParameter(
this.getClass().getDeclaredMethod("verifyCard", YourClassName.class), 0), errors);
I have actual method below:
public ResponseEntity<Message> catEnter(#PathVariable("catId") BigInteger catId, #RequestBody Catrequest catReq, HttpServletRequest request) throws CatDataException, InvalidCatExcecatption {
Message message = new Message();
try {
message = catManager.submitData(catReq.getMessage(), catId, request);
} catch (IOException e) {
throw new CatDataAppException(e.getMessage());
}
return (ResponseEntity<Message>) restResponse(message, request.getMethod());
// Getting null pointer exception in above line
}
I am using mockito for my test code as below:
#Test
public void submitData() throws Exception {
Message mes = new Message();
mes.setCode("00");
mes.setMessage("hi");
ResponseEntity<Message> responseentity = ((ResponseEntity<Message>) catController.catEnter(BigInteger.valueOf(3431), catRequest, mockRequest));
}
I'm getting null pointer exception, Message going as a null, even I set the value explicitly?
Here:
You pass mockRequest when making that call to your production code:
ResponseEntity<Message> responseentity = ... catController.catEnter(... mockRequest));
And your production call does:
return (ResponseEntity<Message>) restResponse(message, request.getMethod());
So the only conclussion: mockRequest is null!
So, first make sure that the passed variable is not null; like:
Request mockedRequest = mock(Request.class);
Or, use the #Mock annotation in case that mockedRequest is a field in your test class.
On top of that; you probably want to do some mock-specification, like:
when(mockedRequest.getMethod()).thenReturn( whatever )
But beyond that, you are lacking a lot of the fundamental basics of Java:
naming conventions: variable names go camelCase, like entityResponse. And typically, tests are named like testCatEnter to express the method that is tested.
You have casts ... where they are not required.
You have quite some code there ... that is unused, like the mes declaration in your test method.
Long story short: I have the feeling that you are overburdening yourself dramatically. First learn the basics; then go for the advanced Mockito stuff.
I am using netbeans to make webservices, I want to make composite webservice using PBEL,
I face a problem in throwing exception in each service, I define complex Type in the schema of the exception I want to throw, and I make it in WSDL too , but inside the service I don't know how can I throw the exception , Here's the example I am working on :
#WebService(serviceName = "CreditCardService", portName = "CreditCardPort", endpointInterface = "org.netbeans.j2ee.wsdl.creditcard.CreditCardPortType", targetNamespace = "http://j2ee.netbeans.org/wsdl/CreditCard", wsdlLocation = "WEB-INF/wsdl/NewWebServiceFromWSDL/CreditCard.wsdl")
public class NewWebServiceFromWSDL implements CreditCardPortType {
public org.netbeans.xml.schema.creditcard.CreditCardResponseType isCreditCardValid(org.netbeans.xml.schema.creditcard.CreditCardType creditCardInfoReq) throws IsCreditCardValidFault {
List<CreditCardType> creditCards = parseCreditCardsFile();
CreditCardResponseType creditCardResponseElement = new CreditCardResponseType();
for (CreditCardType aCreditCard : creditCards) {
if (creditCardInfoReq.getCreditCardNo() == Long.parseLong(String.valueOf(aCreditCard.getCreditCardNo())) {
creditCardResponseElement.setValid(true);
return creditCardResponseElement;
}
}
throws IsCreditCardValidFault(); //here I want to throw an exception .
}
Please can Someone help?
throws IsCreditCardValidFault(); //here I want to throw an exception .
needs to be written as
throw new IsCreditCardValidFault();
throws is used in your declaration of the method, where the throw keyword is used inside the method to indicate where you will throw the exception.
so as an example
try {
//do something which generates an exception
}catch(Exception e){
throw e;
}
but in your case, you want to initiate the exception yourself so you have to create a new object of that exception type. You will create the exception yourself, so no need to enclose in a try/catch block.
throw new IsCreditCardValidFault();