I have created one method
#RequestMapping(value = "/settings/userSettings/{key}", method = RequestMethod.POST)
#Secured("ROLE_HOME_TAB")
public ModelAndView updateUserSetting(HttpServletRequest request,
#PathVariable("key") String key,
#RequestParam(defaultValue = "") String value) {
Map<Object, Object> model = new HashMap<Object, Object>();
try {
User user = RequestUtils.getUser(request);
UserSettings userSettings = userManager.getUserSettings(user,
key);
if (userSettings == null) {
userSettings = new UserSettings(user, key);
}
userSettings.setValue(value);
userManager.saveObject(userSettings);
} catch (Exception e) {
log.error("", e);
}
return new ModelAndView(new JSONView(
model));
}
But while I am starting server I am getting this error
Superclass has no null constructors but no arguments were given
Could not generate CGLIB subclass of class
In my UserSetting pojo class I am checking not null for key. How to resolve this?
I have to use #PathVariable only, I can't use #RequestParam so please help me
PLease try :
The class you are going to proxy using CGLib has to provide a default constructor.
Source : http://forum.springsource.org/showthread.php?50210-Superclass-has-no-null-constructors-but-no-arguments-were-given
Related
In Spring, is it possible to use #JsonView on URL query parameter objects? I can do it for #RequestBody but we don't have bodies in GET requests. This question is specifically for URL query parameters that have been converted to objects by Spring.
For example, I want to have a controller with this mapping:
#GetMapping("/user")
ResponseEntity<UserDTO> searchUser(#JsonView(value = UserView.Searchable.class) UserDTO userQuery) {
//Do some work here using userQuery object for searching users
return ResponseEntity.ok();
}
UserDTO:
public class UserDTO {
#JsonProperty("id")
#JsonView(UserView.Private.class)
private String id= null;
#JsonView(UserView.Searchable.class)
#JsonProperty("city")
private String city = null;
#JsonProperty("country")
#JsonView(UserView.Searchable.class)
private String country = null;
#JsonProperty("state")
private String state = null;
#JsonProperty("zipCode")
private String zipCode = null;
//More properties and getter/setters...etc
}
So if I wanted to call the endpoint I could create a URL like
localhost:8080//api/user?country=Canada to search for a user in Canada but if I tried localhost:8080//api/user?id=123, the property would be ignored.
EDIT:
I might have rushed this idea. There is no JSON de-serialization from url parameters because they are not JSON. Spring creates the query object from ServletModelAttributeMethodProcessor. Perhaps if I want some custom behavior I need to implement HandlerMethodArgumentResolver and do it myself.
EDIT 2
I'm a bit new to Spring so I have a lot to learn but I think what Ill do is just use #InitBinder to whitelist the fields for binding
#InitBinder
public void setSearchableFields(WebDataBinder binder) {
binder.setAllowedFields(
"city",
"country"
);
}
In one of my projects, I have used a POJO just for the query params. I doubt any property would be ignored by default in spring, you can have null checks to ignore.
QueryParams.java
#Data
public class QueryParams {
Integer page;
Integer pageSize;
String sortBy;
Sort.Direction direction;
String searchId;
String status;
String symbol;
public PageRequest getPageRequest(){
if(this.page==null){
this.page = 0;
}
if(this.pageSize==null){
this.pageSize = 25;
}
if(this.sortBy==null){
this.sortBy = "createdAt";
}
if(this.direction ==null){
this.direction = Sort.Direction.DESC;
}
return PageRequest.of(this.page, this.pageSize, Sort.by(this.direction, this.sortBy));
}
}
And my controller :
#GetMapping("currencies")
public ResponseEntity<Page<CurrencyConfig>> getAllCurrencies(#Valid QueryParams queryParams) {
try {
return ResponseEntity.ok(orderbookService.getAllCurrencyConfig(queryParams));
} catch (HttpClientErrorException | HttpServerErrorException e) {
throw new ResponseStatusException(e.getStatusCode(), e.getMessage());
} catch (Exception e) {
e.printStackTrace();
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
e.getLocalizedMessage());
}
}
We are developing a project Using Spring boot with DGS Netflix graphql. We are created all the schemas and datafethers which is working absolutely fine with a default endpoint "/graphql". we would like to expose this app with custom endpoing so we are trying to add a controller with a custom endpoint as below. But When i run the application and send a query, my data fetcher is called twice . first time called from controller and second time i believe from framework it self. Anybody has any thoughts on this why its being called twice and how to avoid it? You help is highly appreciated. Please see the below Datafetcher and Controller.
Controller:
#RestController
#RequestMapping("/sample-information/model")
#Slf4j
public class CustomController {
#Autowired
DgsQueryExecutor dgsQueryExecutor;
#PostMapping(consumes = {MediaType.APPLICATION_JSON_VALUE, "application/graphql"})
public Mono<ResponseEntity<Object>> getDetails(#RequestBody String query,
#RequestHeader HttpHeaders headers
) {
GraphQLQueryInput inputs = null;
try {
inputs = ObjectMapperHelper.objectMapper.readValue(query, GraphQLQueryInput.class);
} catch (Exception e) {
log.error("TraceId: {} - Application Error: Error message: Error converting query to GraphQLQueryInput: {} "+ query);
}
if(inputs.getVariables() == null) {
inputs.setVariables(new HashMap<>());
}
if(inputs.getOperationName() == null) {
inputs.setOperationName("");
}
final String que = inputs.getQuery();
final Map<String, Object> var = inputs.getVariables();
final String opn = inputs.getOperationName();
ExecutionInput.Builder executionInput = ExecutionInput.newExecutionInput()
.query(inputs.getQuery())
.operationName(inputs.getOperationName())
.variables(inputs.getVariables());
return Mono.fromCallable(()-> {
return dgsQueryExecutor.execute(que, var, opn);
}).subscribeOn(Schedulers.elastic()).map(result -> {
return new ResponseEntity<>(result, HttpStatus.OK);
});
}
}
Datafetcher:
#DgsComponent
#Slf4j
public class SampleDataFetcher {
#Autowired
SampleBuilder sampleBuilder;
#DgsData(parentType = DgsConstants.QUERY_TYPE, field = DgsConstants.QUERY.SampleField)
public CompletableFuture<StoreDirectoryByStateResponse> getStoreDirectoryByState(#InputArgument String state, DataFetchingEnvironment dfe) throws BadRequestException {
Mono<StoreDirectoryByStateResponse> storeDirectoryResponse = null;
try {
sampleResponse = sampleBuilder.buildResponse(modelGraphQLContext);
} catch (BaseException e) {
}
return sampleResponse.map(response -> {
return response;
}).toFuture();
}
}
I am trying to improve my Spring MVC application to use a global exception handler to catch various persistence exceptions across all my controllers. This is the controller code that runs when the user tries to save a new StrengthUnit object for example. All the validations work perfectly fine and the form is correctly returned with an error message underneath the name field when the PersistenceException is thrown. The resulting page also correctly contains the strengthUnit attribute and is able to bind the field (this entity just has a name field) back to the form :
#RequestMapping(value = {"/newStrengthUnit"}, method = RequestMethod.POST)
public String saveStrengthUnit(#Valid StrengthUnit strengthUnit, BindingResult result, ModelMap model) throws Exception
{
try
{
setPermissions(model);
if (result.hasErrors())
{
return "strengthUnitDataAccess";
}
strengthUnitService.save(strengthUnit);
session.setAttribute("successMessage", "Successfully added strength unit \"" + strengthUnit.getName() + "\"!");
}
catch (PersistenceException ex)
{
FieldError error = new FieldError("strengthUnit", "name", strengthUnit.getName(), false, null, null,
"Strength unit \"" + strengthUnit.getName() + "\" already exists!");
result.addError(error);
return "strengthUnitDataAccess";
}
return "redirect:/strengthUnits/list";
}
I am trying to use this as a starting point to incorporate the global exception handler that i built and I don't understand how that handler can be called and return the same page with the same model and binding result. I have tried something extremely ugly with a custom exception just to try and understand the mechanics and get the handler to return me the same page as before and I'm unable to get it to work.
Here is the custom exception I built :
public class EntityAlreadyPersistedException extends Exception
{
private final Object entity;
private final FieldError error;
private final String returnView;
private final ModelMap model;
private final BindingResult result;
public EntityAlreadyPersistedException(String message, Object entity, FieldError error, String returnView, ModelMap model, BindingResult result)
{
super(message);
this.entity = entity;
this.error = error;
this.returnView = returnView;
this.model = model;
this.result = result;
}
public Object getEntity()
{
return entity;
}
public FieldError getError()
{
return error;
}
public String getReturnView()
{
return returnView;
}
public ModelMap getModel()
{
return model;
}
public BindingResult getResult()
{
return result;
}
}
Here is my modified catch block in my controller's saveStrengthUnit method :
catch (PersistenceException ex)
{
FieldError error = new FieldError("strengthUnit", "name", strengthUnit.getName(), false, null, null,
"Strength unit \"" + strengthUnit.getName() + "\" already exists!");
result.addError(error);
throw new EntityAlreadyPersistedException("Strength unit \"" + strengthUnit.getName() + "\" already exists!", strengthUnit, error,
"strengthUnitDataAccess", model, result);
}
And finally the global exception handler's method to catch it :
#ExceptionHandler(EntityAlreadyPersistedException.class)
public ModelAndView handleDataIntegrityViolationException(HttpServletRequest request, Exception ex)
{
EntityAlreadyPersistedException actualException;
actualException = ((EntityAlreadyPersistedException)ex);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName(actualException.getReturnView());
modelAndView.addObject(BindingResult.MODEL_KEY_PREFIX + "strengthUnitForm", actualException.getResult());
if (actualException.getEntity() instanceof StrengthUnit)
{
modelAndView.addObject("strengthUnit", (StrengthUnit)actualException.getEntity());
}
return modelAndView;
}
This is extremely ugly and probably very foolish to an experienced Spring developer but I am not quite one (yet). This works BUT the binding result is lost and the validation errors do not appear. How can I modify this code to behave as it was before while still using the global exception handler to handle all errors?
Thanks!
If you are trying to catch the valid exception , which was throw when you are using the #Valid .And you want same handler handle that exception ,then add one more exception class in the #ExceptionHandler annotation
What the doc says
The #ExceptionHandler value can be set to an array of Exception
types. If an exception is thrown matches one of the types in the list,
then the method annotated with the matching #ExceptionHandler will be
invoked. If the annotation value is not set then the exception types
listed as method arguments are used.
The exception thrown by the #Valid annotation is MethodArgumentNotValidException , So you can add this exception on same handler method
I hope this may help you
1.you are setting the entity as strengthUnit.getName() not strengthUnit
throw new EntityAlreadyPersistedException("Strength unit \"" + strengthUnit.getName() + "\" already exists!", strengthUnit, error,
"strengthUnitDataAccess", model, result);
2.but you are checking if (actualException.getEntity() instanceof StrengthUnit
Hope it helps, Try to set the entity as strengthUnit.
#GET
#Path("/paises/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response findCuntryList(#PathParam("id")int id){
try{
ArrayList<Country> lista = new ArrayList<>();
for(int i=0; i<10 ;i++){
Country c = new Country();
c.setId(i);
c.setName("country"+i);
c.setCode("countryIsoCode"+i);
c.setRegion("region"+i);
lista.add(c);
}
Country co = lista.stream().filter(x -> x.getId()==id).findAny().get();
if(id > lista.size()-1) throw new Exception("That id is not correct");
return Response.ok(co).build();
}catch(Exception e){
return Response.status(404).entity(e.getMessage()).build();
}
}
I wanna return a json when i don't have a Exception but when i have it i need to return a string with the exception message but this drop error of json parse.
A single quoted string is a valid JSON. So you could use:
return Response.status(404).entity("\"" + e.getMessage() + "\"").build();
However I advise you to return a JSON object instead. It gives you the flexibility to return extra metadata about the error.
You could use a Map<String, Object>:
Map<String, Object> errorDetails = new HashMap<>();
errorDetails.put("message", e.getMessage());
return Response.status(404).entity(errorDetails).build();
Or create a class for the error details:
public class ErrorDetails {
private String message;
...
}
ErrorDetails errorDetails = new ErrorDetails;
errorDetails.setMessage(e.getMessage());
return Response.status(404).entity(errorDetails).build();
For reporting problems in an HTTP API, have a look at the RFC 7807.
why are you not interested to use WILDCARD expression like,
#Path("getSupportEmail/{broadcastMprId}")
#GET
#Produces(MediaType.MEDIA_TYPE_WILDCARD)
public Response getSupportEmailByBroadcastMprId(#PathParam("broadcastMprId") Integer broadcastMprId) {
return Response.ok(broadcastMprBean.getSupportEmailByBroadcastMprId(broadcastMprId)).build();
}
From the sample code you provided and the tags for this question, you are probably better off using an Exception handler rather than catching and returning a hand-crafted message, and letting your #GET method return your domain object. The JAX-RS library (Jersey in this case?) will serialize it to JSON since your method is annotated with APPLICATION_JSON.
https://dennis-xlc.gitbooks.io/restful-java-with-jax-rs-2-0-en/cn/part1/chapter7/exception_handling.html
For Jersey specifically: https://howtodoinjava.com/jersey/jax-rs-jersey-custom-exceptions-handling-with-exceptionmapper/
I have 3 methods below. The first one calls the second one and the second one calls the third. The junit test fails because all the methods are 'void', and I used an object to test junit.
public class Ids
{
#PUT
#Path("/{otherId}")
#Produces("application/xml")
//First method:
public Response putTag
(
#Context SecurityContext context
, #Context HttpServletRequest req
, #Context HttpServletResponse resp
, #PathParam("otherId") String otherId
, #FormParam("userId") String userId
) {
Map<String, String> obj = new Hashtable<String, String>();
obj.put("userId", userId);
obj.put("otherId", otherId);
putTagMethod(obj);
return ResponseBuilder.buildResponse("Inserted tag records", MediaType.APPLICATION_XML);
}
//Second Method
public void putTagMethod(Map<String, String> obj) {
String userId = obj.get("userId");
String entryId = obj.get("otherId");
try {
updateTag(userId, otherId);
} catch (java.sql.SQLException e) {
LOGGER.error("java.sql.SQLException: ", e);
e.printStackTrace();
}
}
//Third Method
public static void updateTag(String userId, String otherId) throws PersistenceException, {
if (...some condition) {
throw new InvalidParameterException("blah blah blah");
}
SpecialData data = null;
//Update if found, else insert
if (dataList != null && dataList.size() > 0) {
data = dataList.get(0);
update(userId, otherId);
} else {
insert(userId, otherId);
}
How do I write a Junit test to test 'Response putTag' method?
I wrote this (below) junit, but it gives error (
#Test
public void testPutTag() throws Exception
{
Ids tags = new Ids();
Map<String,String> obj = new HashMap<String,String>();
String xml = tags.putTag(obj);
assertTrue("PUT", xml.equals(
"<result>insert</result>"));
}
I'm getting error:
Incompatible types
required: Map<String, String>
found: void
problem is I need to assign 'xml' to a return type but all my methods are void.
How do I solve this?
Anyone please advise...