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);)
Related
I have this catch statement:
catch (NotFoundException ex) {
ex.getError().setTitle(NOT_FOUND);
throw new NotFoundException(resource, id, ex.getError());
}
How can I mock this exception? I've tried this
when(service
.filter(eq(any()), eq(any()), eq(any())))
.thenThrow(new NotFoundException(anyString(), anyString()));`
But it gives me a null exception error because of this line:
ex.getError().setTitle(NOT_FOUND);
The constructor is:
public NotFoundException(String resource, String id, Error error) {
this.resource = resource;
this.ids = Collections.singletonList(id);
this.error = error;
}
And I can't get the exception variable to set the title, or find an way to mock it.
Thanks for you help!
.thenThrow(new NotFoundException(anyString(), anyString()));
This isn't allowed: anyString() only stands directly in for the call in when and verify. In your call to filter, simply use any() rather than eq(any()), but you're otherwise using matchers in the correct place.
Furthermore, it looks like your system-under-test assumes that ex.getError() is non-null; it is likely that you'll need to pass in a useful Error instance as constructor parameter into the NotFoundException you create.
.thenThrow(new NotFoundException("foo", "bar", new Error(/* ... */)))
Naturally, if your Error is difficult to create or work with, you might use a mock(Error.class) instead.
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'm getting the following findbugs error:
"Method call passes null for nonnull parameter : Null passed for nonnull parameter of getApiStatus(ApiResponse)"
If the apiResponse is null in the CallApi method (not shown here for brevity's sake), it simply throws an exception that is caught in handleApiException and thrown again if we can't do anything else about the exception.
There is no way that a null value for apiResponse could be passed into getApiStatus() method at the botton of this code snippit. How can I tell findbugs that this is the case without doing yet another null check on top of the null check that is done in the apiService.CallApi method? I've tried using the NonNull annotation, but that didn't resolve the issue. Here's the code in question:
ApiResponse apiResponse = null;
try {
apiResponse = apiService.CallApi(apiURL, requestObject);
}
catch (ApiException ex) {
handleApiException(ex);
}
boolean apiStatus = getApiStatus(apiResponse);
Any Ideas?
My suggestion would be to NOT handle the exception, but to set this method as throws ApiException. And then handle it higher up the chain. If your code gets an exeption in that try block, then handles the exception in the catch, then apiResponse can easily be null. And will then go on to try the getApiStatus method, hence passing in a null.
public void yourMethod() throws ApiException {
ApiResponse apiResponse = apiService.CallApi(apiURL, requestObject);
boolean apiStatus = getApiStatus(apiResponse);
// Whatever else you need to do here.
}
Your only other option is to put the apiStatus call below the apiResponse one inside the try block, like so:
ApiResponse apiResponse = null;
try {
apiResponse = apiService.CallApi(apiURL, requestObject);
boolean apiStatus = getApiStatus(apiResponse);
} catch (ApiException ex) {
handleApiException(ex);
}
Or, as you say, do a null check before calling getApiStatus, but that's not as preferable as the options above.
In your code, the getApiStatus(apiResponse) will be called regardless of the ApiException occurring or not.
You should have this instead:
try {
ApiResponse apiResponse = apiService.CallApi(apiURL, requestObject);
// line bellow will not execute if CallApi throws ApiException
boolean apiStatus = getApiStatus(apiResponse);
}
catch (ApiException ex) {
handleApiException(ex);
}
// lines bellow will execute after try-catch block above
// regardless of the ApiException occurring or not
If CallApi throws an exception, then it will be handled and control will continue to getApiStatus, without apiResponse ever being assigned anything other than the initial null.
I am coding a web-app in Java-EE and find myself with a very unexpected result when I am trying to display errors on user-input.
The app is built on the JSP/Servlet/Form/Bean model. Basically, the JSP stores data in the request, and transfers it to the servlet. Then the servlet transfers the request raw to the form, which then reads the data, performs the necessary checks and returns the bean to the servlet.
Most of the fields must have specific values, some others must simply be non-null.
I have written error detection code to secure inputs however I find myself with a very strange result:
when the field is non-null but the value is incorrect (say, an hour located outside the 00:00-23:59 range), it does return the proper error, along with the error message, stored in a HashMap, and I can access it in my JSP.
However, when the field is null, it returns the message, probably stores it in the HashMap as well (I know this because the ${!empty errors.dataErrors} test returns true and the error field is displayed in my JSP) but there's no way to access the values of the errors
I have searched through my code but still can't find where the error comes from. Here are snippets of it if someone knows where the problem comes from
doPost method from the servlet:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
NewBookingForm form = new NewBookingForm();
Booking booking = form.registerBooking(request);
String VUE;
request.setAttribute("booking", booking);
request.setAttribute("errors", form);
this.getServletContext().getRequestDispatcher(VIEW).forward(request, response);
}
the map is a field in the NewBookingForm class, declared and initialized outside the registerBooking method like this private Map<String,String> dataErrors = new HashMap<String,String>(); and it has a private setter (for access within the class) and a public getter (for access in the Servlet and in the JSP)
inside the form class, I use this function to get the field values:
private static String getFieldValue(HttpServletRequest request, String fieldName)
{
String value = request.getParameter(fieldName);
if (value == null || value.trim().length() == 0){return null;}
else{return value;}
}
After getting the values with a series of calls like String fieldDepartureStation = getFieldValue(request, FIELD_DEPARTURE_STATION); at the beginning of my method, I then check them using try/catch blocks like this
try
{validation.departureStation(fieldDepartureStation);}
catch(Exception e)
{setDataErrors(FIELD_DEPARTURE_STATION, e.getMessage());}
The validations method within the validation class are a bit different if the data must have specific value-ranges or must simply be non-null.
In the former case, they are something like this:
public void departureTime(String time) throws Exception
{
if (!validationRETime(time)) { throw new Exception("Please input a time with the hh:mm pattern"); }
}
....
private boolean validationRETime(String strTime)
{
String regExp = "^([01][0-9]|2[0-3])[:][0-5][0-9]$"; // hh:mm
if (strTime.matches(regExp))
{
return true;
}
else
{
return false;
}
}
whereas in the latter case they are simply
public void departureStation(String station) throws Exception
{
if (station.equals(null)) { throw new Exception("Please input a departure station"); }
}
Finally, in my JSP, I use the following code to display errors:
<c:if test="${!empty errors.dataErrors}">
<p>Errors</p>
<c:forEach items="${errors.dataErrors}" var="message">
<p><c:out value="${message.value}" /></p>
</c:forEach>
</c:if>
And it does display the Error paragraph when I purposedly enter incorrect values, but the <c:forEach> is only looping and displaying the error messages when the wrong field is non-null but with an incorrect value. Thus with a field that only needs to be non-null, I never get the message (but I do get the error)
These are all the things I could think of that could possibly go wrong, but I have yet to discover where they did and if someone could help me, I'd be very glad.
The problem is in your departureStation method: -
public void departureStation(String station) throws Exception
{
if (station.equals(null)) {
throw new Exception("Please input a departure station");
}
}
Your test for null value is itself triggering a NPE. So, as soon as station.equals(null) is executed for station = null, a NPE exception is thrown, which is then propagated to the caller. So, your if block will not even be executed. And hence you are not throwing the Exception as you might be thinking.
Now, also note that, the NPE that is thrown does not contain any message. So, e.getMessage() will return null on it.
Now, let's move back to the caller: -
try
{validation.departureStation(fieldDepartureStation);}
catch(Exception e)
{setDataErrors(FIELD_DEPARTURE_STATION, e.getMessage());}
Here you are doing the biggest Crime in the world of Exception Handling, by using a catch block for Exception. Since Exception is the super class of all the exceptions, it will handle all the exceptions in the same way. So, it consumes the NPE, and passes it to setDataErrors().
So, you will of course get the errors, but, the value e.getMessage() will be null. And that is why you are not seeing any message. You can even test it by logging the value of e.getMessage() in the catch block above.
Solution ??
Just change your null check with this one: -
if (station == null) {
throw new Exception("Please input a departure station");
}
And everything will be ok. I think, you will have to do this change in all of your methods. Always perform the null check using == operator.
public class Test {
public static void main(String[] args) {
Test c = new Test ();
try {
c.departureTime("30:30");
} catch (Exception e) {
System.out.println(e.getMessage());
}
try {
c.departureTime(null);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public void departureTime(String time) throws Exception {
if (!validationRETime(time)) {
throw new Exception("Please input a time with the hh:mm pattern");
}
}
private boolean validationRETime(String strTime) {
String regExp = "^([01][0-9]|2[0-3])[:][0-5][0-9]$"; // hh:mm
if (strTime.matches(regExp)) {
return true;
} else {
return false;
}
}
}
You will figure out your problem by running above code. Simply putting, you need to make sure exp.getMessage() always has value. To fix the issue, you might want to tweak your departureTime() method to provide more fine-grained exception handling.