I am trying to insert data in tables of DB with one single API. And using Factory Design Pattern for implementing this. I have createtd an interface and every service class is implementing its method addNewData and we have a Factory class which has addData Method but that ethod is not returning anything and getting null in tagetTable variable(this is in service class code appended) and because of which method is not working and data in not inserting.
**
The error getting is :
**
"Cannot invoke "addDataInDBDao.addNewData(InputStream,HttpHeaders)" because "targetTable" is null"
This is Factory Class
//Factory Class
public class addDataInDBFactoryService {
static Map<String,addDataInDBDao> creators=new HashMap<>();
public addDataInDBFactoryService(){
creators.put("configurations",new ConfigurationsService()); //configurations is the table name and ConfigurationService is a class
creators.put("component_org_mapping",new ComponentService());
}
public static addDataInDBDao addData(String tableName){
return creators.get(tableName);
}
}
This is the Service Class through which I'm implementing the API.
#Component
#Path(PathConstants.ADD_DATA)
public class AddDataInDBService {
CustomLogger logger = LoggerFactory.getLogger();
#POST
#Path(PathConstants.ADD_DATA_IN_DB)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response addData(#QueryParam("tableName") String tableName, InputStream incomingData, #Context HttpHeaders headers){
addDataInDBDao targetTable = addDataInDBFactoryService.addData(tableName);
return targetTable.addNewData(incomingData,headers);
}
}
The interface
public interface addDataInDBDao{
public Response addNewData(InputStream incomingData, #Context HttpHeaders headers);
}
The method calling in Service class with same name as method created in interface. I am using this by calling constructor in put method. An its working fine
public Response addNewData(InputStream incomingData, #Context HttpHeaders headers){
logger.info();
/
/
/
logger.infoEndOfMethod();
return Response.status(responseStatus).entity(jsonInString).build();
} catch (IOException e) {
return DataUtils.prepareServerErrorWithMessage(e, UtilityErrors.IO_ERROR_IN_REQUEST.getErrorCode().getMessage());
} catch (IhubException e) {
return DataUtils.prepareServerErrorWithMessage(e, e.getMessage());
}
}
But This is the function which is already written and it has different name and I cant change its name but need to call this method in my code.
public Response addComponentMappings(InputStream incomingData, #Context HttpHeaders headers){
logger.info();
/
/
/
/
return Response.status(responseStatus).entity(jsonInString).build();
} catch (IOException e) {
return DataUtils.prepareServerErrorWithMessage(e, UtilityErrors.IO_ERROR_IN_REQUEST.getErrorCode().getMessage());
} catch (IhubException e) {
return DataUtils.prepareServerErrorWithMessage(e, e.getMessage());
}
}
Configurations is a table and ConfigurationService is a Class which is implementing the interface addDataInDBDao and its method addNewData. But the Factory Methods addData is not returning anything and hence the targetTable variable is null. Please help if anything is wrong in code.
Related
I have some code like this
#Controller
class SomeController
#GetMapping("/someAsync")
#ResponseBody
public String someAsync() {
throw new SomeException();
}
#GetMapping("/somePage")
public String somePage() {
throw new SomeException();
}
in this case, i want to redirect to default error page for "/somePage"
and I need to response like { HttpStatus:500, message: "something happened" }
I made this ControllerAdvice
#ControllerAdvice
class SomeAdvice
#ExceptionHandler(Exception.class)
#ResponseBody
public Object handle(Exception e) {
// in this method, I want to know this Exception was called by a method that contains "#ResponseBody"
}
Could I know the method signature like this way?
So I've been using Spring and Java for a while to build microservices. I am concerned by the way I am currently handling service layer results which uses "business exception"
Controller
#RestController
public class PurchaseController {
#Autowired
private PurchaseService purchaseService;
#PostMapping("/checkout")
public ResponseEntity<?> checkout(#RequestBody CheckoutRequest body) {
try {
SomeDTO dto = purchaseService.doCheckout(body);
return ResponseEntity.ok(dto);
}
catch (UnauthorizedException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage());
}
catch (CustomBusinessException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
}
}
Service
#Service
public class PurchaseService {
// ...
public DTO doCheckout(CheckoutRequest request) {
// this one calls another microservice
if (!isUserValid(request.userId)) {
// current handling of business rules violation (1)
throw new UnauthorizedException("User not valid");
}
if (request.total < 10) {
// current handling of business rules violation (2)
throw new CustomBusinessException("Minimum checkout at 20 dollars");
}
// ... do actual checkout
return new DTO(someDTOData);
}
}
I was comfortable at using this "pattern" because I do not need to "if" the business result in the controller level to return the appropriate HttpStatusCode, but since I've found some articles saying that exception is expensive specifically in Java, I doubt what I was doing is good for the long run.
Is there another correct way to gracefully handles the business result layer?
The problem with ResponseEntity in Spring is that they are typed with the result object you want to return when the endpoint is called successfully, so you can't return another body different from the happy path one, that in your case would be SameDTO. One way to address this issue is to use ? as the type of the response entity, as you have done but it is not the most recommended way.
So the best way to do this is precisely to use exceptions when there is a situation when you can't return the expected object and you have to return another object or status code, but instead of using a try-catch in the controller you should use an exception handler (Controller Advice) https://www.baeldung.com/exception-handling-for-rest-with-spring.
This controller advice would catch any exception thrown in your application and depending on the exception type it could return a different response class or status code without affecting the main controller. One example of how can be your controller advice would be:
#ControllerAdvice
public class ErrorHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleInternal(final RuntimeException ex) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ex.getMessage());
}
#ExceptionHandler(UnauthorizedException.class)
public ResponseEntity<ResponseDto> identityClientException(UnauthorizedException e) {
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.body(e.getMessage());
}
#ExceptionHandler(CustomBusinessException.class)
public ResponseEntity<ResponseDto> identityClientException(CustomBusinessException e) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(e.getMessage());
}
And your controller woulb be much more clean without exception handling logic:
#RestController
public class PurchaseController {
#Autowired
private PurchaseService purchaseService;
#PostMapping("/checkout")
public ResponseEntity<SomeDTO> checkout(#RequestBody CheckoutRequest body){
SomeDTO dto = purchaseService.doCheckout(body);
return ResponseEntity.ok(dto);
}
}
I am currently using Spring MVC and Hibernate to develop my web app. Still learning inner workings of java.
I find my self in a situation where I need to store data in a field that could accept different type of Objects along with some other strings of data. More precisely I want to create a ReturnObject that could hold messages, error code...etc. This way my return JSON could stay consistent through out the api.
This is how I created my ReturnObject
public class ReturnResponse {
//Set fields
private Object returnObj; <----- Need this to accept different types
private HttpStatus httpStatus;
private String message;
private String developerMessage;
// Start build
public ReturnResponse(){
this.returnObj = returnObj;
this.httpStatus =.....etc.
}
// Setters... getters...
}
private Object returnObj; so that this field could accept Collection, Maps, Class..etc but is this safe?
I seem to remember that its always a good practice to declare specific object type in the field to ensure type-safe.
Questions
Do you see foreseeable problem in the future, is there a better way of doing this?
If this is not type safe, how would I make it safer.
You can use a generic :
public class ReturnResponse<ObjectType> {
private ObjectType returnObj;
private HttpStatus httpStatus;
private String message;
private String developerMessage;
public ReturnResponse(ObjectType returnObj, /*other parameters...*/) {
this.returnObj = returnObj;
// set other parameters
}
public ObjectType getReturnObj() {
return this.returnObj;
}
// ...
}
It will work if you know when you instanciate your ReturnResponse what's the type of the returned object.
I use this pattern in most of my API without problem.
If you want "to store data in a field that could accept different type of Objects along with some other strings of data." then you need to have a base class for that object which in your case will probably be Object.
The problem is that you need to have some way to decipher later in your code, what type of object that is - which in most cases I think will be undesirable and will require unsafe casting.
Only way I can think of to make it more safe is to make some kind of wrapper like:
public class Bean {
private String string;
private Integer integer;
private List<String> list;
private Bicycle bicycle;
//setters
//...
public Optional<Bicycle> getBicycle() {
return Optional.ofNullable(bicycle);
}
//... and so on...
}
The error handler should be in the controller and it should respond an http error. That means a correct HTTP error status, and a desired error message. An error should not look like a successful request (No status code 200). It's an error. In your front end you should handle the http error response accordingly.
With spring this can be very easy a nicely done. Here is an example of an error handler of a project of mine. It's an own class with the annotation #ControllerAdvice. spring will automatically use that.
This class will automatically catch any unhandled exception that are defined with #ExceptionHandler and send in my case a ShortExceptionResponse that contains the type and the message of the exception thrown, with a correct Http error status defined with #ResponseStatus.
In your front end you can react accordingly to the different HTTP status error codes. It's nice and generic.
#ControllerAdvice
public class RestExceptionResponseHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(SetRestController.class);
#ExceptionHandler(NoSuchElementException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public #ResponseBody
ShortExceptionResponse noSuchElementExceptionHandler(Exception ex) {
LOGGER.error("An error occured processing a rest request", ex);
return new ShortExceptionResponse(ex);
}
#ExceptionHandler(value = {EntityAlreadyExistsException.class})
#ResponseStatus(HttpStatus.FORBIDDEN)
public #ResponseBody
ShortExceptionResponse entityAlreadyExistsExceptionHandler(EntityAlreadyExistsException ex) {
LOGGER.debug("A rest request could not been process due an illegal state of the target entity", ex);
return new ShortExceptionResponse(ex);
}
#ExceptionHandler(value = {IllegalArgumentException.class, UnsupportedOperationException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
public #ResponseBody
ShortExceptionResponse illegalArgumentExceptionHandler(Exception ex) {
LOGGER.error("An error occured processing a rest request", ex);
return new ShortExceptionResponse(ex);
}
#ExceptionHandler(value = {HttpMessageNotReadableException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
public #ResponseBody
ShortExceptionResponse httpMessageNotReadableExceptionHandler(Exception ex) {
LOGGER.error("An error occured processing a rest request", ex);
if (ex.getCause() instanceof InvalidFormatException) {
return new ShortExceptionResponse(new InvalidValueException(((InvalidFormatException) ex.getCause()).getOriginalMessage()));
}
return new ShortExceptionResponse(ex);
}
...
...
}
In the actual controller you just keep throwing the exception and it will be handled by your error handler
#RequestMapping(method = RequestMethod.POST)
public #ResponseBody
MetadataDTO createMetadata(#RequestBody MetadataDTO metaDataDTO) throws EntityAlreadyExistsException {
MetadataDTO result = metaDataService.createMetadata(metaDataDTO.getName(), metaDataDTO.getDescription(), metaDataDTO.getType());
return result;
}
You can create a 'model' class to store the full object to be converted to json:
#AllArgsConstructor //or make a constructor with all the fields manually
class ResponseObject {
User user;
House house;
Car car;
}
Since you are using Spring, you already have the Jackson library. So you can do:
#Autowired ObjectMapper objectMapper; // no need to configure anything to use this
public String getJson(){
User user = new User("user", "password");
House house = new House(4, true, ...);
Car car = new Car();
ResponseObject resp = new ResponseObject(user, house, car);
String json = null;
json = objectMapper.convertValue(resp, ResponseObject.class);
// or:
try {
json = objectMapper.writeValueAsString(resp);
} catch (Exception e) {
...
}
// or: (would need to use a google Gson dependency)
Gson gson = new Gson();
json = gson.toJson(resp, ResponseObject.class);
return json;
}
Alternatively, if you really need the flexibility,
#Autowired ObjectMapper mapper;
public void printJson() {
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("number", 5);
jsonMap.put("String", "string");
jsonMap.put("kanky", 987L);
String json = mapper.writeValueAsString(jsonMap);
System.out.println("json: " + json);
} // works fine if your map values have a toString defined
So I am build an mvc application using Jersey. A method that accepts Path parameters (#PathParam).
If a custom exception is thrown (ExampleException) then a 404 Not Found response is returned using an exception mapper.
#Provider
public class ExampleExceptionMapper implements ExceptionMapper<ExampleException> {
#Override
public Response toResponse(ExampleException ex) {
return Response.status(Status.NOT_FOUND).entity("Not Found - " + ex.getMessage()).build();
}
}
However, I am implementing #FormParam's so a user POSTs to the server. The same exact exception is raised, but instead I should return a 400 Bad Request response. Without modifying the exception how would I be able to make the exception mapper return the proper response code?
Simplest way is create multiple ExceptionMappers, each for specific subclass of ExampleException.
But you want to have the same exception for both cases and decide whether to throw 404 for GET/PathParam and POST/FormParam, you can inject the request into the mapper and check what method it is:
#Provider
public class ExampleExceptionMapper implements ExceptionMapper<ExampleException> {
#Context Request request;
#Override
public Response toResponse(ExampleException ex) {
if ("POST".equals(requset.getMethod()))
return Response.status(Status.BAD_REQUEST).build();
else
return Response.status(Status.NOT_FOUND).entity("Not Found - " + ex.getMessage()).build();
}
}
If you want to decide by PathParams, you can inject UriInfo:
#Provider
public class ExampleExceptionMapper implements ExceptionMapper<ExampleException> {
#Context UriInfo info;
#Override
public Response toResponse(ExampleException ex) {
if (info.getPathParameters().isEmpty())) //please make better condition based on your needs
return Response.status(Status.BAD_REQUEST).build();
else
return Response.status(Status.NOT_FOUND).entity("Not Found - " + ex.getMessage()).build();
}
}
I am using methods like this
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<UserWithPhoto> getUser(#RequestHeader(value="Access-key") String accessKey,
#RequestHeader(value="Secret-key") String secretKey){
try{
return new ResponseEntity<UserWithPhoto>((UserWithPhoto)this.userService.chkCredentials(accessKey, secretKey, timestamp),
new HttpHeaders(),
HttpStatus.CREATED);
}
catch(ChekingCredentialsFailedException e){
e.printStackTrace();
return new ResponseEntity<UserWithPhoto>(null,new HttpHeaders(),HttpStatus.FORBIDDEN);
}
}
And I want to return some text message when exception occurs but now I just return status and null object. Is it possible to do?
As Sotirios Delimanolis already pointed out in the comments, there are two options:
Return ResponseEntity with error message
Change your method like this:
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity getUser(#RequestHeader(value="Access-key") String accessKey,
#RequestHeader(value="Secret-key") String secretKey) {
try {
// see note 1
return ResponseEntity
.status(HttpStatus.CREATED)
.body(this.userService.chkCredentials(accessKey, secretKey, timestamp));
}
catch(ChekingCredentialsFailedException e) {
e.printStackTrace(); // see note 2
return ResponseEntity
.status(HttpStatus.FORBIDDEN)
.body("Error Message");
}
}
Note 1: You don't have to use the ResponseEntity builder but I find it helps with keeping the code readable. It also helps remembering, which data a response for a specific HTTP status code should include. For example, a response with the status code 201 should contain a link to the newly created resource in the Location header (see Status Code Definitions). This is why Spring offers the convenient build method ResponseEntity.created(URI).
Note 2: Don't use printStackTrace(), use a logger instead.
Provide an #ExceptionHandler
Remove the try-catch block from your method and let it throw the exception. Then create another method in a class annotated with #ControllerAdvice like this:
#ControllerAdvice
public class ExceptionHandlerAdvice {
#ExceptionHandler(ChekingCredentialsFailedException.class)
public ResponseEntity handleException(ChekingCredentialsFailedException e) {
// log exception
return ResponseEntity
.status(HttpStatus.FORBIDDEN)
.body("Error Message");
}
}
Note that methods which are annotated with #ExceptionHandler are allowed to have very flexible signatures. See the Javadoc for details.
Here is an alternative. Create a generic exception that takes a status code and a message. Then create an exception handler. Use the exception handler to retrieve the information out of the exception and return to the caller of the service.
http://javaninja.net/2016/06/throwing-exceptions-messages-spring-mvc-controller/
public class ResourceException extends RuntimeException {
private HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
public HttpStatus getHttpStatus() {
return httpStatus;
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {#link #initCause}.
* #param message the detail message. The detail message is saved for later retrieval by the {#link #getMessage()}
* method.
*/
public ResourceException(HttpStatus httpStatus, String message) {
super(message);
this.httpStatus = httpStatus;
}
}
Then use an exception handler to retrieve the information and return it to the service caller.
#ControllerAdvice
public class ExceptionHandlerAdvice {
#ExceptionHandler(ResourceException.class)
public ResponseEntity handleException(ResourceException e) {
// log exception
return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
}
}
Then create an exception when you need to.
throw new ResourceException(HttpStatus.NOT_FOUND, "We were unable to find the specified resource.");
Evaluating the error response from another service invocated...
This was my solution for evaluating the error:
try {
return authenticationFeign.signIn(userDto, dataRequest);
}catch(FeignException ex){
//ex.status();
if(ex.status() == HttpStatus.UNAUTHORIZED.value()){
System.out.println("is a error 401");
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
return new ResponseEntity<>(HttpStatus.OK);
}
return new ResponseEntity<>(GenericResponseBean.newGenericError("Error during the calling the service", -1L), HttpStatus.EXPECTATION_FAILED);