How to manipulate Optional Spring #RequestParam - java

I'm new to JPA.
I have a class like this
#Table(name="student")
#Entity
public class Student{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int studentId;
#Column
#Size(max = 20)
private String name;
#Column
#Min(value = 2014)
#Max(value = 2020)
private int yearOfBirth;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "classroomId")
Classroom classroom;
//Getters and setters
}
My repository:
#Repository
public interface HocSinhRepository extends JpaRepository<Student, Integer> {}
My controller:
public class StudentController {
#Autowired
StudentRepository studentRepository;
#GetMapping(value = "/get")
public Page<Student> get(#RequestParam Optional<Integer> page, #RequestParam Optional<String> sortBy) {
return studentRepository.findAll(
PageRequest.of(page.orElse(0), 3, Sort.Direction.ASC, sortBy.orElse("name"))
);
}
}
By using Optional.orElse, I can assign a default value to the sortBy parameter if it's null. How can I do the same thing if the parameter is not null, but just a non-sensible string (like "asdasd")?

You can use the map operator of optionals.
So it would be
sortBy.map(o -> {
if (o.equalsIgnoreCase("asdasd")){
return "name";
} else {
return o;
}
}).orElse("name"));
This will make the optional return the value "name" when it is empty or when the containing value exists and is with ignore case "asdasd". In every other case it will return the original value it contained.
So your code will be adapted to be
return studentRepository.findAll(
PageRequest.of(page.orElse(0), 3, Sort.Direction.ASC,
sortBy.map(o -> {
if (o.equalsIgnoreCase("asdasd")){
return "name";
} else {
return o;
}}).orElse("name"));
));

variation on #xerx593's VALID_SORT_FIELDS and making spring's #RequestParam optional
public static final Set<String> VALID_SORT_FIELDS = Set.of("name", "studentId");
#GetMapping(value = "/get")
public Page<Student> get(
#RequestParam(required = false, defaultValue = "0") Integer page,
#RequestParam(required = false, defaultValue = "name") String sortBy) {
String sortByOrDefault = VALID_SORT_FIELDS.contains(sortBy) ? sortBy : "name";
return studentRepository.findAll(PageRequest.of(page, 3, Sort.Direction.ASC, sortByOrDefault));
}

another variation:
#GetMapping(value = "/get")
public Page<Student> get(
#RequestParam(required = false, defaultValue = "0") Integer page,
#RequestParam(required = false, defaultValue = "name") String sortBy) {
String sortByOrDefault = SortConfig.STUDENTS.getSortableFields().contains(sortBy)
? sortBy
: SortConfig.STUDENTS.getDefaultSortField();
return studentRepository.findAll(PageRequest.of(page, 3, Sort.Direction.ASC, sortByOrDefault));
}
public enum SortConfig {
STUDENTS(List.of("name", "studentId")),
ANOTHER_ENTITY(List.of("field1", "field2"));
private String defaultSortField;
private List<String> sortableFields;
private SortConfig(List<String> sortableFields) {
this.sortableFields = sortableFields;
}
public String getDefaultSortField() {
return defaultSortField;
}
public List<String> getSortableFields() {
return sortableFields;
}
}

A common scenario would be:
To have the "valid field names" stored in a "data structure", e.g., like:
public static final Set<String> VALID_SORT_FIELDS = Set.of("name", "studentId"/*, all we "consider valid"...*/);
Then we can use it in our controller like:
#GetMapping(value = "/get")
public Page<Student> get(#RequestParam Optional<Integer> page, #RequestParam Optional<String> sortBy) {
final String sort = sortBy
.map( s ->
s != null && VALID_SORT_FIELDS.contains(s)?
s : "name" // or a consatant com.domain.my...DEFAULT_SORT
)
.get();
return studentRepository.findAll(
PageRequest.of(page.orElse(0), 3, Sort.Direction.ASC, sort)
);
}
When we want to ignore the case, we would adjust to:
...&& VALID_SORT_FIELDS.contains(s.toLowerCase(/*some (default) Locale*/))
Another/additional possible approach: validaion-api... but the wrapping Optional is a "challange"(??)...

Related

How to apply Hibernate validator when data submitted via POST and omit when PUT?

Have the same DTO object for POST and PUT methods:
class AcmeRequest {
private String id;
#NotEmpty
private String productCode;
private String description;
}
For POST request I always expect to see productCode field, that's why I specified #NotEmpty annotation but when PUT request received productCode should be optional.
Is it possible some how just to skip #NotEmpty when request is PUT?
Every Hibernate Validator annotation has a groups parameter. Through interfaces, you can control which validations are activated. See more at docs.
In controller level, specify which groups must be activated with the #Validated annotation.
Below, there is a small example from one of my demo projects. I once had the same question as you.
Entity:
#Entity
#Table(name = "tasks")
#Getter #Setter
public class Task
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Null(message = "You can't provide a task ID manually. ID's are automatically assigned by our internal systems.", groups = {TaskInsertValidatorGroup.class})
#NotNull(message = "You must provide an id" , groups = TaskUpdateValidatorGroup.class)
private Integer id;
#NotBlank(message = "Task description cannot be empty")
#Length(max = 255 , message = "Task description length must not exceed 255 characters")
private String description;
#JsonProperty("is_completed")
#Column(name = "is_completed")
private Boolean isCompleted = false;
#CreationTimestamp
#JsonProperty("created_on")
#JsonFormat(pattern="dd-MM-yyyy HH:mm:ss")
#Column(name = "created_on", updatable = false)
private Timestamp creationDate;
#UpdateTimestamp
#JsonProperty("last_modified")
#JsonFormat(pattern="dd-MM-yyyy HH:mm:ss")
#Column(name = "last_modidied")
private Timestamp lastModificationDate;
#Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Task task = (Task) o;
return id.equals(task.id);
}
#Override
public int hashCode()
{
return Objects.hash(id);
}
}
Interfaces:
public interface TaskInsertValidatorGroup {}
public interface TaskUpdateValidatorGroup{}
Controller:
RestController
#RequestMapping("/api")
public class TaskRestController
{
#Autowired
private TaskService taskService;
#GetMapping("/tasks/{id}")
public ResponseEntity<?> getTask(#PathVariable Integer id)
{
return new ResponseEntity<>(taskService.findTask(id),HttpStatus.OK);
}
#GetMapping("/tasks")
public ResponseEntity<?> getTasks()
{
return new ResponseEntity<>(taskService.findAllTasks(),HttpStatus.OK);
}
#PostMapping("/tasks")
public ResponseEntity<?> addTask(#Validated(TaskInsertValidatorGroup.class) #RequestBody Task task)
{
taskService.saveTask(task);
APISuccessResponse response = APISuccessResponse.builder()
.info("Task added")
.build();
return new ResponseEntity<>(response,HttpStatus.OK);
}
#RequestMapping(value = "/tasks" , method = RequestMethod.PATCH)
public ResponseEntity<?> updateTask(#Validated(TaskUpdateValidatorGroup.class) #RequestBody Task task)
{
taskService.updateTask(task);
APISuccessResponse response = APISuccessResponse.builder()
.info("Task Updated")
.build();
return new ResponseEntity<>(response,HttpStatus.OK);
}
#RequestMapping(value = "/tasks/{id}", method = RequestMethod.DELETE)
public ResponseEntity<?> removeTask(#PathVariable Integer id)
{
taskService.removeTask(id);
APISuccessResponse response = APISuccessResponse.builder()
.info("Task Deleted")
.build();
return new ResponseEntity<>(response,HttpStatus.OK);
}
}

how to add subquery into specification in Java

I wish to have subquery, which provides me filtering actors by name.
I have a rest controller's method, which returns list of actors as JSON from movie base on movieId. I try to add filters as specification, but I have no idea how to write proper query. Base on "Spring Data JPA Specification for a ManyToMany Unidirectional Relationship" I found solution for subquery, which returns me all actors to proper movie base on movieId. Now I try to write this query.
Actor entity
#Data
#NoArgsConstructor
#Entity
#Table(name = "actors")
public class Actor implements Serializable {
private static final long serialVersionUID = 6460140826650392604L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "actor_id")
private Long actorId;
#Column(name = "first_name")
private String firstName;
#ManyToMany(mappedBy = "actors")
#ToString.Exclude
private List<Movie> movie = new ArrayList<>();
#JsonIgnore
public List<Movie> getMovie() {
return this.movie;
}
}
Movie entity
#Data
#Entity
#NoArgsConstructor
#Table(name = "movies")
public class Movie implements Serializable {
private static final long serialVersionUID = 3683778473783051508L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id")
private Long movieId;
private String title;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(name = "movies_actors"
, joinColumns = { #JoinColumn(name = "movie_id") }
, inverseJoinColumns = { #JoinColumn(name = "actor_id") })
private List<Actor> actors = new ArrayList<>();
#JsonIgnore
public List<Actor> getActors() {
return this.actors;
}
}
//Rest Controller
#CrossOrigin(origins = "http://localhost:3000")
#RestController
#RequestScope
#RequestMapping("/rest")
public class ActorRestController {
private ActorService actorService;
private MovieService movieService;
#Autowired
public ActorRestController(ActorService actorService, MovieService movieService) {
this.actorService = actorService;
this.movieService = movieService;
}
.
.
.
#GetMapping("movies/{movieId}/actors")
public ResponseEntity<Page<Actor>> getAllActorsFromMovieByIdMovie(#PathVariable(name = "movieId") Long movieId, Pageable pageable) {
Optional<Movie> movieFromDataBase = movieService.findMovieById(movieId);
if (movieFromDataBase.isPresent()) {
return new ResponseEntity<>(actorService.findAllActors(ActorSpec.query(movieId), pageable), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
.
.
}
// Specification for actor
#NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ActorSpec {
public static Specification<Actor> query(final Long movieId) {
return (root, query, cb) -> {
query.distinct(true);
Subquery<Movie> movieSubQuery = query.subquery(Movie.class);
Root<Movie> movie = movieSubQuery.from(Movie.class);
Expression<List<Actor>> actors = movie.get("actors");
movieSubQuery.select(movie);
movieSubQuery.where(cb.equal(movie.get("movieId"), movieId), cb.isMember(root, actors));
return cb.exists(movieSubQuery);
};
}
}
I would like, my code will return filtered actors by name ex.:
http://localhost:8080/rest/movies/48/actors?name=Collin
will return me
{ "actorId": 159,
"firstName": "Collin",
"lastName": "Konopelski",
"age": 21
},
but in case I do not sent any request param (http://localhost:8080/rest/movies/48/actors), let program return me all actors. I don't want to create new endpoint only for #Requestparam cause, this one is used by UI created in React.
Thanks!
Ok I found,
My solution:
RestController
#GetMapping("movies/{movieId}/actors")
public ResponseEntity<Page<Actor>> getAllActorsFromMovieByIdMovie(#PathVariable(name = "movieId") Long movieId,
#RequestParam(name = "name", required = false) String name,
Pageable pageable) {
Optional<Movie> movieFromDataBase = movieService.findMovieById(movieId);
if (movieFromDataBase.isPresent()) {
return new ResponseEntity<>(actorService.findAllActors(ActorSpec.query(movieId ,name), pageable), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
Specification
#NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ActorSpec {
public static Specification<Actor> query(final Long movieId, String name) {
return (root, query, cb) -> {
Predicate predicateMovieID = getPredicateByMovieId(movieId, root, query, cb);
if (Strings.isNotBlank(name)) {
Predicate a = cb.and(predicateMovieID, cb.equal(root.get("firstName"), name));
Predicate b = cb.and(predicateMovieID, cb.equal(root.get("lastName"), name));
return cb.or(a,b);
}
return cb.and(predicateMovieID);
};
}
private static Predicate getPredicateByMovieId(Long movieId, Root<Actor> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
query.distinct(true);
Subquery<Movie> movieSubQuery = query.subquery(Movie.class);
Root<Movie> movie = movieSubQuery.from(Movie.class);
Expression<List<Actor>> actors = movie.get("actors");
movieSubQuery.select(movie);
movieSubQuery.where(cb.equal(movie.get("movieId"), movieId), cb.isMember(root, actors));
return cb.exists(movieSubQuery);
}
}

Validate Request body in spring using #Valid

I am want to validate a JSON object, for length of an attribute. I am using #Size annotation to specify maximum length as shown below.
#JsonRootName("question")
public class QuestionJson {
#JsonProperty(value = "id", required = false)
private Long id;
#JsonProperty(value = "text", required = true)
private String label;
#JsonProperty(value = "answers", required = true)
private List<AnswerJson> answers;
}
#JsonRootName("answer")
public class AnswerJson {
#JsonProperty(value = "id", required = false)
private Long id;
#JsonProperty(value = "type", required = true)
private String type;
#JsonProperty(value = "label", required = true)
#Size(message = "size should not be long", max = 10)
private String label;
}
My request mapping in controller looks like:
#RequestMapping(value = "/api/answer", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public AnswerJson createQuestion(#RequestHeader(HttpHeaders.AUTHORIZATION) final String authorizationHeader, #Valid #RequestBody final QuestionJson questionJson) {
// some code here....
return answer;
}
UPDATE: Validation works on the outer elements eg. text in my case but fails on the nested list.
Every time we use #Valid annotation we also include a BindingResult instance as a method parameter, it contains the #Valid marked parameter errors if any:
public final #ResponseBody String theMethod(
final #Valid ValidableObjectImpl validableObject,
BindingResult result) {
try {
if (result.hasErrors()) {
for (FieldError error : result.getFieldErrors()){
// do something
}
// return error
}
} catch (Exception e) {
// ...
}
}
Found the solution. We need add #Valid annotation to the before the declaration of the nested object. eg
#JsonRootName("question")
public class QuestionJson {
#JsonProperty(value = "id", required = false)
private Long id;
#JsonProperty(value = "text", required = true)
private String label;
#JsonProperty(value = "answers", required = true)
#Valid
private List<AnswerJson> answers;
}

Mapping hibernate entity with Jackson annotation

I'm working with Spring, hibernate and MySql but I have some problem with seralization of query result.
First in my entity I added #JsonManagedReference on Set structure (#OneToMany side) and #JsonBackReference on single object reference (#ManyToOne side) and it works but I wasn't be able to retrieve all needed information (for example #ManyToOne reference).
So i swapping #JsonBackReference on set structure and #JsonManagedReference on single object but I retrieve
No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst744_f["handler"])
I tried also with #JsonIgnore on Set structure but it doesn't work for the same issues.
This is my spring configuration
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
// properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
properties.put("hibernate.enable_lazy_load_no_trans",true);
return properties;
and this is part of one of my several entities:
/**
* Car generated by hbm2java
*/
#Entity
#Table(name = "car", catalog = "ATS")
public class Car implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer idCar;
#JsonManagedReference
private CarType carType;
#JsonManagedReference
private Fleet fleet;
private String id;
private int initialKm;
private String carChassis;
private String note;
#JsonBackReference
private Set<Acquisition> acquisitions = new HashSet<Acquisition>(0);
public Car() {
}
public Car(CarType carType, Fleet fleet, int initialKm, String carChassis) {
this.carType = carType;
this.fleet = fleet;
this.initialKm = initialKm;
this.carChassis = carChassis;
}
public Car(CarType carType, Fleet fleet, String id, int initialKm, String carChassis, String note,
Set<Acquisition> acquisitions) {
this.carType = carType;
this.fleet = fleet;
this.id = id;
this.initialKm = initialKm;
this.carChassis = carChassis;
this.note = note;
this.acquisitions = acquisitions;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id_car", unique = true, nullable = false)
public Integer getIdCar() {
return this.idCar;
}
public void setIdCar(Integer idCar) {
this.idCar = idCar;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_carType", nullable = false)
public CarType getCarType() {
return this.carType;
}
public void setCarType(CarType carType) {
this.carType = carType;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_fleet", nullable = false)
public Fleet getFleet() {
return this.fleet;
}
public void setFleet(Fleet fleet) {
this.fleet = fleet;
}
#Column(name = "id", length = 5)
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
#Column(name = "initialKm", nullable = false)
public int getInitialKm() {
return this.initialKm;
}
public void setInitialKm(int initialKm) {
this.initialKm = initialKm;
}
#Column(name = "carChassis", nullable = false, length = 20)
public String getCarChassis() {
return this.carChassis;
}
public void setCarChassis(String carChassis) {
this.carChassis = carChassis;
}
#Column(name = "note", length = 100)
public String getNote() {
return this.note;
}
public void setNote(String note) {
this.note = note;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "car")
public Set<Acquisition> getAcquisitions() {
return this.acquisitions;
}
public void setAcquisitions(Set<Acquisition> acquisitions) {
this.acquisitions = acquisitions;
}
}
one method that uses the query:
#Override
#RequestMapping(value = { "/cars/{idFleet}"}, method = RequestMethod.GET)
public #ResponseBody TableUI getCars(#PathVariable int idFleet) {
TableUI ajaxCall=new TableUI();
try {
ajaxCall.setData(fleetAndCarService.findCarsByIdFleet(idFleet));
return ajaxCall;
} catch (QueryException e) {
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
LOG.error("Threw exception in FleetAndCarControllerImpl::addCar :" + errorResponse.getStacktrace());
return ajaxCall;
}
}
two class for the query:
public interface DefRdiRepository extends JpaRepository<DefRdi, Integer>{
//#Query("SELECT CASE WHEN COUNT(c) > 0 THEN true ELSE false END FROM DefRdi c WHERE c.parName = ?1 AND c.description= ?2")
//Boolean existsByParNameAndDescription(String parName, String description);
//Query method of spring, I put findBy and then the key of research
DefRdi findByParNameAndDescription(String parName, String description);
}
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
Where is my error? I don't want Set object but only the single reference. The problem is only when I serialize. Thanks
UPDATE:
I use #JSonIgnore on all set collectionts and Eager instead lazy ad all works fine, but is there a way to retrieve all the information only when I want, for example having two different query?
So it doesn't work
#Override
#Transactional
public List<Car> findByFleetIdFleet(int idFleet) {
List<Car> carList= carRepository.findByFleetIdFleet(idFleet);
for (Car car:carList){
Hibernate.initialize(car.getCarType());
Hibernate.initialize(car.getFleet());
}
return carList;
// return carRepository.findByFleetIdFleet(idFleet);
}
All collections need to be fetched eagerly when loading them from data base, in order to get serialized by Spring. Make sure you fetch them eagerly (e.g. FetchMode.JOIN). You could also swap #JsonManagedReference from wanted fields with #JsonIgnore to black listed fields, Spring automatically serialises every field without annotation.
Update:
Changing the data repository to something like that should work, I am not sure it compiles, but I think you will get the point:
#EntityGraph(value = "some.entity.graph", type = EntityGraph.EntityGraphType.FETCH)
#Query(
value = "SELECT c FROM Car c INNER JOIN FETCH c.acquisitions WHERE c.id = :idFleet"
)
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
For more information look at this post and read the official documentation.
Workaround:
There seems to be a workaround, however fetching those collections eager like shown above should have a positive performance impact, since there is no need for loading proxies afterwards. Also no open transactions are needed at controller level.

java service 400 bad request error

Dear spring Java professionals
please help me out in this :
I have a custom service in spring and I dont have any errors on my wildfly server when i run it . but when I do the below update request i am getting 400 bad request though im sending the format as specified in my controller
inside my controller :
#RequestMapping(value = "/user/updatefilters/{Id}", method = RequestMethod.POST)
public Response updateFilter(#PathVariable("Id") Long Id, #RequestBody #Valid Filter Filter) {
FilterService.updateFilter(Id, Filter);
HashMap<String, Object> response = new HashMap<>();
response.put("messages", null);
response.put("success", Boolean.valueOf(true));
return Response.instance().friendlyName("filter-updated").object(response).statusCode(HttpStatus.OK);
}
inside my service file :
public void updateFilter(Long Id,Filter Filter) {
List<Filter> currentFilter = FilterRepo.getFilters(Id, Filter.getFilterId().longValue(),null);
currentFilter.get(0).setLabel(Filter.getLabel());
FilterRepo.save(currentFilter.get(0));
for (FilterField FilterField : Filter.getFilterFields()) {
FilterField currentFilterField = FilterFieldRepo.getFilterField(FilterField.getfieldId());
if (currentFilterField != null) {
currentFilterField.setfield(FilterField.getfield());
currentFilterField.setTypeId(FilterField.getTypeId());
FilterFieldRepo.save(currentFilterField);
}
}
}
inside my repository :
public List<Filter> getFilterList(Long Id, String type) {
List<Filter> FilterField = FilterFieldRepo.getFilterFields(Id,type);
return FilterField;
}
public void updateFilter(Long Id,Filter Filter) {
List<Filter> currentFilter = FilterRepo.getFilters(Id, Filter.getFilterId().longValue(),null);
currentFilter.get(0).setLabel(Filter.getLabel());
FilterRepo.save(currentFilter.get(0));
for (FilterField FilterField : Filter.getFilterFields()) {
FilterField currentFilterField = FilterFieldRepo.getFilterField(FilterField.getfieldId());
if (currentFilterField != null) {
currentFilterField.setfield(FilterField.getfield());
currentFilterField.setTypeId(FilterField.getTypeId());
FilterFieldRepo.save(currentFilterField);
}
}
}
Please note that inside my entity I added a transient list like this :
#Transient
private List<FilterField> filterFields;
updated :
this is my Filter class i generated the crud in netbeans but added the transuent list manually:
#Entity
#Table(schema="hitmeister",name = "filters")
#NamedQueries({
#NamedQuery(name = "Filter.findAll", query = "SELECT s FROM Filter s"),
#NamedQuery(name = "Filter.findByFilterId", query = "SELECT s FROM Filter s WHERE s.filterId = :filterId"),
#NamedQuery(name = "Filter.findById", query = "SELECT s FROM Filter s WHERE s.Id = :Id"),
#NamedQuery(name = "Filter.findByLabel", query = "SELECT s FROM Filter s WHERE s.label = :label"),
#NamedQuery(name = "Filter.findByInsertionDate", query = "SELECT s FROM Filter s WHERE s.insertionDate = :insertionDate"),
#NamedQuery(name = "Filter.findByIsActive", query = "SELECT s FROM Filter s WHERE s.isActive = :isActive"),
#NamedQuery(name = "Filter.findByType", query = "SELECT s FROM Filter s WHERE s.type = :type")})
public class Filter implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "filter_id")
private Integer filterId;
#Basic(optional = false)
#NotNull
#Column(name = "id")
private int Id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 500)
#Column(name = "label")
private String label;
#Basic(optional = true)
#Column(name = "insertion_date")
#Temporal(TemporalType.TIMESTAMP)
private Date insertionDate;
#Column(name = "is_active")
private Boolean isActive;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 20)
#Column(name = "type")
private String type;
#Transient
private List<FilterField> filterFields;
public Filter() {
}
public Filter(Integer filterId) {
this.filterId = filterId;
}
public Filter(Integer filterId, int Id, String label, Date insertionDate, String type) {
this.filterId = filterId;
this.Id = Id;
this.label = label;
this.insertionDate = insertionDate;
this.type = type;
}
public Integer getFilterId() {
return filterId;
}
public void setFilterId(Integer filterId) {
this.filterId = filterId;
}
public int getId() {
return Id;
}
public void setuserId(int Id) {
this.userId = userId;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public Date getInsertionDate() {
return insertionDate;
}
public void setInsertionDate(Date insertionDate) {
this.insertionDate = insertionDate;
}
public Boolean getIsActive() {
return isActive;
}
public void setIsActive(Boolean isActive) {
this.isActive = isActive;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#Override
public int hashCode() {
int hash = 0;
hash += (filterId != null ? filterId.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Filter)) {
return false;
}
Filter other = (Filter) object;
if ((this.filterId == null && other.filterId != null) || (this.filterId != null && !this.filterId.equals(other.filterId))) {
return false;
}
return true;
}
#Override
public String toString() {
return " Filter #"+ filterId ;
}
public List<FilterField> getFilterFields() {
return filterFields;
}
public void setFilterFields(List<FilterField> filterFields) {
this.filterFields = filterFields;
}
}
If you need my entity code i can post it as well
Thanks In advance !
My first recommendation: (OP tried and it didn't work, she was sending POST request)
Change your mapping as below and I think you should be fine. Request from browser address bar is a GET request.
As you can see below, HTTP 400 comes when server is unable to understand the request client is sending, and in your case you are sending GET but server has nothing for GET but for POST, so 400.
W3C HTTP 400
10.4.1 400 Bad Request
The request could not be understood by the server due to malformed
syntax. The client SHOULD NOT repeat the request without
modifications.
Code fix:
#RequestMapping(value = "/user/updatefilters/{Id}", method = RequestMethod.GET)
My second recommendation:
I am not Spring expert but here are my 2 cents you can try based on the JSON object you have provided and your Filter mapping - (1.) Change userId to Id, (2.) Have insertionDate as NULL, instead of an empty string.
Make sure your JSON string variables are mapped case-sensitively with your Filter class mapping, and their values are compatible with reference types.
Either your request format is not what Spring expects, or one of the Filter validations is failing. Add a org.springframework.validation.Errors argument and dump the values to find out what validations failed.
public Response updateFilter(#PathVariable("Id") Long Id, #RequestBody #Valid Filter Filter, Errors filterErrors) {
You can sniff the actual traffic using curl or a network monitoring tool to make sure the HTTP transaction is really what you think it is.
EDIT: Having looked at the JSON in one of your comments, I think this is going to turn out to be upper/lower case in your JSON field names. Either change "Id" to "id" and "FilterId" to "filterId", or annotate the Filter fields with #XmlElement(name = "Id") and #XmlElement(name = "FilterId"). Java Bean property names are case sensitive.
EDIT 2: Filter.setuserId(int Id) is broken as well. You need a setId() method for deserializing the bean, and you need to change the method so it stores the passed argument instead of just setting userId to itself.

Categories

Resources