Jersey: Returns 204 Status Instead of 500 - java

I have a Jersey web service with the following a resource class:
#Stateless
#Path("/provision")
public class ProvisionResource
{
private final Logger logger = LoggerFactory.getLogger(ProvisionResource.class);
#EJB
private ProvisionService provisionService;
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("/subscriber")
public SubscriberAccount querySubscriberAccount(
#QueryParam("accountNum") String accountNum)
{
logger.debug("Entering querySubscriberAccount()");
final SubscriberAccount account;
try
{
account = provisionService.querySubscriber(accountNum);
if (account != null)
{
logger.debug("Retreived account = " + account);
}
else
{
logger.debug("No account was found for " + accountNum);
}
}
catch (IllegalArgumentException ex)
{
logger.error("Illegal argument while executing query for subscriber account",
ex);
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}
catch (Exception ex)
{
logger.error("Unexpected exception while executing query for subscriber account",
ex);
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
logger.debug("Exiting querySubscriberAccount()");
return account;
}
.... snip ....
}
The provisionService.querySubscriber throws an exception which is caught by the second catch statement in the querySubscriberAccount method (we see the log statement in the file). However, the client is receiving a 204 status instead of the expected 500 error.
I did find this issue which is similar to mine: http://java.net/jira/browse/JERSEY-41 but is quite old and for Jersey 1.3.1. We are using version 1.9.1.
Has anyone else seen this issue and hopefully figured out what the problem is?

I have created a bug http://java.net/jira/browse/JERSEY-1062 for this issue. Please consider voting for it if you are experiencing the same problem.

Related

Where should I throw custom exceptions and catch Exception object

I am coding a Spring MVC, hibernate app. I can't decide where should I throw custom exceptions, what custom exceptions to throw and where to catch "Exception", in controller or service or DAO?
I tried to throw a custom exception in controller and service and catch "Exception" in the controller as the last catch block. But every time a custom exception is thrown, the last catch block( of Exception) catches it and throws CustomGenericException overriding the previous one.
//Controller
#PostMapping("/add/{user_id}/{book_id}")
public #ResponseBody
String addToCart(#PathVariable("user_id") Integer user_id,
#PathVariable("book_id") Integer book_id){
try {
return cartService.addBook(user_id, book_id);
}
catch (HibernateException | CannotCreateTransactionException dbException) {
throw new DatabaseDownException("Database error. Could not connect at this time.");
}
catch (Exception ex){
throw new CustomGenericException("Could not add book to cart at this time. Please try again later.");
}
}
//Service
#Override
public String addBook(int user_id, int book_id) {
if(bookDAO.getCount(book_id)>0) {
Cart cart = new Cart(user_id, book_id);
List<Cart> userCarts = cartDAO.getCart(user_id, 0);
for (Cart c : userCarts) {
if (c.getBook_id() == book_id) {
return "Book already in cart!";
}
}
List<Cart> issuedBooks =cartDAO.getCart(user_id, 1);
for(Cart c:issuedBooks){
if(c.getBook_id()==book_id){
return "Book already issued. Can't add another to cart.";
}
}
return cartDAO.addBookToCart(cart);
}
return "No more copies left. Please try again later.";
}
I want to know where should I throw exceptions, where to catch them and how to avoid custom thrown exceptions getting caught by last catch block.
#aks If you want to throw checked exceptions than you should pass "cause" exception to constructor of exception on higher level (in this case the last one catch) because otherwide the cause information is lost. Core Exception class has constructor with cause parameter to pass.
You can also try to use Controller Advice https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
I hope I helped a little bit :)
read about chained exception in Java here
you are not wrapping exception object in your custom exception , that is why you feel like previous exception is getting overridden .

Code not executed when trying to connecting to WSDL webservice

When trying to use a webservice, a NullPointerException is thrown, and expected log statements are missing in the application's log.
I get a NullPointerException in the following code:
public void useWebservice() {
initEndpoint();
try {
port.usefulFunctionWebserviceProvides(); // NullPointerException is thrown here!
} catch (javax.xml.ws.soap.SOAPFaultException ex) {
log.error("Something went wrong making a request to the webservice");
}
}
The initEndpoint method looks like this:
private volatile Webservice service = null; // instance variable
private WebservicePort port = null; // instance variable
private void initEndpoint() {
String username = "username"; // Loaded from a properties file
String password = "password"; // Loaded from a properties file
LoginResponse loginResponse;
Webservice theService = service;
if (theService == null || port == null) {
synchronized (this) {
theService = service;
if (theService == null) {
try {
log.info("Initializing Endpoint (service & port)"); // This line appears in the log
service = new Webservice();
port = service.getWebservicePort();
final String wsdlUrl = properties.getProperty(WSDL_URL, WSDL_DEFAULT_URL);
((BindingProvider)port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, wsdlUrl);
log.info("EndpointAddress set");
LoginRequestType loginRequest = new LoginRequestType();
loginRequest.setUsername(username);
loginRequest.setPassword(password);
loginResponse = port.login(loginRequest, null, null);
} catch (Exception e) {
try {
log.info("re-Initializing Endpoint (service & port)");
// Try to connect to the webservice using a fallback URL
} catch (Exception e2) {
log.error("Couldn't connect to webservice");
service = null;
throw new CustomException();
}
}
if (loginResponse == null) {
service = null;
throw new CustomException();
}
}
}
}
}
None of the info logging is printed to the log file except for the log message "Initializing Endpoint (service & port)".
I don't understand how the port variable can be null in the useWebservice method. I also expect to see either "EndpointAddress set" or "re-Initializing Endpoint (service & port)" in the log file. But neither are printed to the file.
The code has worked fine before, but has started to give problems after being moved to a new project and used as a dependency.
The problem has been identified, it was a missing dependency. Because of that an error was thrown when the code tried to initialize the port. The catch block only catches exceptions so that code was never executed. If we caught throwable for example we would see the log statements from the catch block.
PS: Initializing the port object as it is done in the initEndpoint method in the question is NOT thread safe! The port needs to be initialized for each request.

Getting Error java.lang.NoClassDefFoundError: sun/net/www/protocol/https/HttpsURLConnectionImpl when deployed in Jboss EAP 6.4.x

I am writing a rest client using java.net which should do a PATCH request. But as PATCH is not a supported method in java.net, I used reflection to make it supported by changing the code like
private void updateConnectionToSupportPatchRequest(final HttpURLConnection conn)
throws ReflectiveOperationException {
try {
final Object targetConn;
if (conn instanceof HttpsURLConnectionImpl) {
final Field delegateField = HttpsURLConnectionImpl.class.getDeclaredField("delegate");
delegateField.setAccessible(true);
targetConn = delegateField.get(conn);
} else {
targetConn = conn;
}
final Field methodField = HttpURLConnection.class.getDeclaredField("method");
methodField.setAccessible(true);
methodField.set(targetConn, "PATCH");
} catch (final NoSuchFieldException ex) {
LOGGER.error("NoSuchFieldException: {} ", ex.getMessage());
}
}
but when I deploy my application which uses my rest client in JBoss, I get this error -
java.lang.NoClassDefFoundError: sun/net/www/protocol/https/HttpsURLConnectionImpl
I looked up on this error and came across this post http://planet.jboss.org/post/dealing_with_sun_jdk_related_noclassdeffounderror_under_jboss
I tried the suggested solution in the post still getting the same error. Any ideas on how to get passed this issue?
P.S. I cannot use the Apache HttpClient or RestEasy(Jboss) as there is another 3PP being used in the project which does not support Apache HttpClient
Have you tried using the workaround X-HTTP-Method-Override before trying to fiddle with internal classes of the JDK? If that's the case, you can use the instance's getClass-method to access fields and use isAssignableFrom as alternative to instanceof.
Another approach to get rid off specifying concrete classes is just trying to get the field in HttpsURLConnection and assuming a non-Https-URLConnection if the field can't be found. This might look like the following code:
private void updateConnectionToSupportPatchRequest(final HttpURLConnection conn)
throws ReflectiveOperationException {
try {
final Object targetConn = conn;
try {
final Field delegateField = findField(conn.getClass(), "delegate");
delegateField.setAccessible(true);
targetConn = delegateField.get(conn);
}
catch(NoSuchFieldException nsfe) {
// no HttpsURLConnection
}
final Field methodField = findField(conn.getClass(), "method");
methodField.setAccessible(true);
methodField.set(targetConn, "PATCH");
} catch (final NoSuchFieldException ex) {
LOGGER.error("NoSuchFieldException: {} ", ex.getMessage());
}
}
private Field findField(Class clazz, String name) throws NoSuchFieldException {
while (clazz != null) {
try {
return clazz.getDeclaredField(name);
}
catch(NoSuchFieldException nsfe) {
// ignore
}
clazz = clazz.getSuperclass();
}
throw new NoSuchFieldException(name);
}
But this might fail at another level because - obviously - the class that is used within JBoss is not the one you implemented the workaround, so fields and methods might be named differently.

Cannot call any method outside my controller in Spring

Situation:
Using Spring MVC I prompt a user in my view to enter some information into the form.
I bind that information to a form object (like normal).
I successfully get data back to my controller (confirmed) via log dump.
The Problem:
Now I'm in the controller with all the data the user entered into the form (bound to a form object).
I take that same object with data in it and I try to pass it to my service class method to use the data in a way I need it to.
The problem is that as soon (as soon) as my controller calls the service method it throws an exception. It doesn't even reach a 'log.info' (which is the first line of code in that method).
This should absolutely be working and I'm very taken back as to why it isn't. It seems like a very simple matter. i.e.(get the data back to my controller; use that data in a call to a service method).
CONTROLLER
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerAccount(#ModelAttribute User user, Locale locale,
Model model) {
String theView = "";
try{
logger.info("User submitted Registration Form");
user.setPaidStatus("ACTIVE");
user.setUserRole("SUBSCRIBER");
logger.info(user.toString()); //Proving all the data is available.
userService.createNewUser(user); //This is the call to my service
//method. As soon as it reaches it it exceptions out right away.
//userDao.createNewUser(userDto); //just to see if it does the same
//thing elsewhere - (it does)
model.addAttribute("command", new User());
theView = "login";
} catch(SaveMyFavsException se){
logger.info(se.getCmdCode() + ", Message: " + se.getCmdMsg());
model.addAttribute("command", new User());
model.addAttribute("error", se.getCmdCode() + ", Message: " +
se.getCmdMsg());
return "register";
} catch(Exception e){
logger.info(e.getLocalizedMessage());
model.addAttribute("command", new User());
model.addAttribute("error", e.getLocalizedMessage());
return "register";
}
return theView;
}
SERVICE CLASS (See createNewUser())
#Component
public class UserService implements UserServiceInterface{
#Autowired
UserDaoInterface userDao;
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
public void createNewUser(User user){
int result = 0;
try{
//FAILS BEFORE MAKING IT HERE (automatically ends up in the second Catch block for Exception with no message)
logger.info("Entered createNewUser() service");
logger.info("User ID: " + user.getUserId());
result = userDao.createNewUser(user);
logger.info("New User DAO Complete - Rows Inserted: " + result);
} catch(SaveMyFavsException se){
throw new SaveMyFavsException(se.getCmdCode(), se.getCmdMsg());
} catch(Exception e){
logger.info("General Exception occurred during service to create new user... Trace: " + e.getLocalizedMessage());
throw new SaveMyFavsException(2000015, "General Exception occurred during service to create new user... Trace: " + e.getLocalizedMessage());
}
}
You're not seeing the full error message because you're eating the full stack trace. Change your logger to:
logger.info("General Exception occurred during service to create new user.", e);
Please share the code which inject the userService to the controller. This seems to be an issue with the bean injection.

use spring data to connect to datastore google cloud

How can i use Spring Data in order to connect to DataStore google, actually i use com.google.api.services.datastore.DatastoreV1
But my lead Manager want use spring-Data with dataStore how can i do that?
for example to insert an Entity i actually use:
public void insert(Entity entity) {
Datastore datastore = this.datastoreFactory.getInstance();
CommitRequest request =
CommitRequest.newBuilder().setMode(CommitRequest.Mode.NON_TRANSACTIONAL)
.setMutation(Mutation.newBuilder().addInsertAutoId(entity)).build();
try {
CommitResponse response = datastore.commit(request);
} catch (DatastoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
#SuppressWarnings("deprecation")
public Datastore getInstance() {
if(datastore != null)
return datastore;
try {
// Setup the connection to Google Cloud Datastore and infer
// credentials
// from the environment.
//the environment variables DATASTORE_SERVICE_ACCOUNT and
DATASTORE_PRIVATE_KEY_FILE must be set
datastore = DatastoreFactory.get().create(
DatastoreHelper.getOptionsfromEnv().dataset(Constant.ProjectId)
.build());
} catch (GeneralSecurityException exception) {
System.err.println("Security error connecting to the datastore: "
+ exception.getMessage());
return null;
} catch (IOException exception) {
System.err.println("I/O error connecting to the datastore: "
+ exception.getMessage());
return null;
}
return datastore;
}
any help will be appreciated
To use Spring Data with a specific storage you need to implement a bunch of interfaces from Spring Data Commons. Take a look at the GCP Spanner Spring Data implementation as an example (https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-data-spanner)

Categories