I just wanted to know how custom validation or any other solution would be implemented on a POJO. My POJO has been used in many ways where i do not need any kind of validation such as #NotBlank etc. However there is a scenario if i want to update at least one field inside it. Then validate it.
My POJO is provided in the request body and i want to validate if one of the field is provided then accept the request else don't. So far i have implemented it in a hard coded way. But i would like something which spring boot provides.
My pojo is below
public class Person {
private String name;
private String age;
private String email;
//etc .etc. getters and setters
}
Now if i want to update a person i want to validate if a single field is provided in the Request Body then accept the payload else throw constraint violation.
So far i have done it hard coded ie
private boolean isInValid(Person per) {
if (per == null) {
return true;
}
int changes = 0;
changes = changes + (StringUtils.isBlank(per.getName()) ? 0 : 1);
changes = changes + (StringUtils.isBlank(per.getEmail()) ? 0 : 1);
//etc etc...
return changes == 0;
}
I would like something that spring boot provides.
thanks
If it is not enough standard Hibernate Validator checks, you can implement your own validators using your custom logic
Related
I have a use case where I am needing to validate incoming requests with a bunch of fields, and if certain ones are null or empty, I want to return a detailed response from my API letting the client know that they need to include a value for that field. I am new to Optionals, and think there may be a more efficient and streamlined way to do this.
I have an incoming request:
public class myRequest {
private String fieldOne;
private String fieldTwo:
..etc
}
And I have validations in place :
if(StringUtils.isEmpty(request.getFieldOne)){
return new MyResponse("Please include a field one value")
}else if(StringUtils.isEmpty(request.getFieldTwo)){
return new MyResponse("Please include a field two value")
}else if(StringUtils.isEmpty(request.getFieldThree){
//etc..
}
Now I would think i converted the incoming requests to an optional, I would be able to validate these fields more efficiently.
Optional<MyRequest> request = Optional.of(request);
request.ifPresent((req ) ->{
//checks if the request itself is null...but what about fields, or objects?
});
Some of the incoming fields are objects themselves as well. Wondering if anyone has come across this.
For the sake of simplicity lets assume I have a Document object with seven fields (but imagine that it can have many more). This object looks something like this:
#Getter
#Setter
public class Document {
private String fileName;
private String fileType;
private String createdBy;
private Date createdAt;
private Date lastModifiedAt;
private List<String> modifiers;
private Long timesModified;
}
I want to create an endpoint which can receive any number of #RequestParam and returns a List<Document> of all the documents which match the given query. For example: return all documents with fileType == doc, which were created between createdAt == 01/01/2021 && createdAt 31/01/2021, modified timesModified == 5 times and modifiers.contains("Alex"). The reason for this is that I want to allow the user to query for documents depending on combination of fields the user wants. Originally to handle this we created the endpoint like so:
#GetMapping(value = {RestApi.LIST})
public ResponseEntity<List<Document>> getDocuments (#RequestParam Map<String, Object> optionalFilters) {
List<Document> documents = documentService.getListOfDocuments(optionalFilters);
if (documents != null) {
return new ResponseEntity<>(documents, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
The problem with this is that because we use optionalFilters as Map<String, Object> this requires us to perform a lot of casting in our code and overall makes our code very tedious and cumbersome because we have to iterate through the whole map and create a custom query depending the fields that were passed. In order to try and improve this I created an OptionalFilters object:
#Getter
#Setter
#NoArgsConstructor
public class OptionalFilters {
private String fileName;
private String fileType;
private String createdBy;
private Date createdAt;
private Date lastModifiedAt;
private List<String> modifiers;
private Long timesModified;
}
And modified the endpoint to this:
#GetMapping(value = {RestApi.LIST})
public ResponseEntity<List<Document>> getDocuments (#Valid OptionalFilters optionalFilters) {
List<Document> documents = documentService.getListOfDocuments(optionalFilters);
if (documents != null) {
return new ResponseEntity<>(documents, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
However, although that this simplifies the way we receive the parameters and extract the values from them, we still need to iterate through all the parameters and create a custom query. Is there some way to elevate and take advantage of Spring-Data (or any other solution) so that I don't have to create a custom query depending on each query param that is passed through? I am using Solr as the repository if this may be any help.
Using Query by Example is one the most simple option but it has its limitations. Excerpt from the above link:
Limitations
Like all things, the Query by Example API has some limitations. For instance:
Nesting and grouping statements are not supported, for example:
(firstName = ?0 and lastName = ?1) or seatNumber = ?2
String matching only includes exact, case-insensitive, starts, ends, contains, and regex
All types other than String are exact-match only
Query by Example is suitable choice if your filtering is never too complicated. But when restirictions like above hit the fan of your CPU cooler the choice is to use Specifications to construct queries.
One big difference is also that Using Query by Example you need to explicitly populate the example by its getters and setters. With specification you can make it in a generic way (with Java generics) using just use field names
In your case you could just pass the map to generic method and create filtering by just looping and adding by and (note that the link's example has static stuff mostly but it has not to be, you just need field name/criterion -pair to loop it in a generic way)
With specifications you can do anything that can be done with Query by Example and almost anything else also. The overhead to get familiar with specifications might be bigger but the advantage using specifications will be rewarding.
In a nutshell:
Spring interface Specification is based on JPA CriteriaQuery and for each you need only to implement one method:
Predicate toPredicate (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder builder);
Repository interfaces needs just to extend JpaSpecificationExecutor<YourClass> When you have a set of predicates, you can - for example -
repository.findAll(Specification.where(spec1).and(spec2));
It might seem complicated or difficult at start but it is not that at all. The greatest advantage with Specification is that you can do almost anything programmatically instead of manipulating JPQL queries or so.
It is so common in UI logic that you have a method to checkValid(something). Its primary use is to return a Boolean. But in case of invalid (or false), we may want to provide an additional user message about what is being invalid, after all the checkValid() method might have checked 20 different things. By simply responding with "not valid" to the user is not very helpful.
So is there a built-in Java class or some from Apache commons that does just that? I understand it is so simple to build my own, but my sense tells me this is so common I must missed it somewhere in common packages.
Status codes have long been used to return "Success" (often 0) or "Failure" responses, with failures further identified by distinct non-zero values. The Enum class is a friendlier way of doing this.
enum Status {
SUCCESS("Success"),
BAD_PATH("The directory does not contain the required file"),
HAS_THE_LETTER_C("The directory must not contain the letter C");
private final String message;
private Status(String _message) {
message = _message;
};
#Override
public String toString() {
return message;
}
}
Status status = checkValid(something);
if (status != Status.SUCCESS) {
// Inform user of specific failure reason
}
Apache commons has a Pair class, so you could use a Pair<Boolean, String>. Alternatively, you could just return a String with the validation failure, and treat a null as non-error (i.e., the validation either returns the reason of a failure or null if there's no failure).
We're setting up a DB with an object model for safes that have bill readers inside to put the bills in. This safe is stored in the Unit class and that unit has a list of placeholders for, let's say, 3 components. Components can change over time, but placeholders will stay connected to the same safe. So this unit has 3 placeholders with identifiers like 'left reader', 'right reader' and 'printer'. The actual component inside such a placeholder has the product type (for instance Mei reader ... or JCM reader ...) and a serial number.
Now, as the unit itself will be requested from the server side quite often as it is shown in one or more (pages of) portals (to see it's own serial number, location, how much money is inside, which users are allowed to log on to this safe, etc.) and components need not be known most of the time we want to lazily load them. The unit itself needs to know it's actual components (configuration) with serial numbers for components to be able to know / tell the back end when a component is exchanged during a servicing by a mechanic.
There is an intermediate table (placeholdercomponents) with placeholder FK, component FK and a datetime placed and a datetime removed.
Right now there is a Unit class that contains, besides a lot else, this:
#OneToMany(mappedBy = "unit", fetch = FetchType.EAGER)
private List<Placeholder> placeholders = new ArrayList<>();
#XmlElementWrapper(name = "Placeholders")
#XmlElement(name = "Placeholder")
public final List<Placeholder> getPlaceholders() {
return placeholders;
}
public final void setPlaceholders(List<Placeholder> pPlaceholders) {
placeholders = pPlaceholders;
}
The placeholder class has this:
#OneToMany(mappedBy = "placeholder", fetch = FetchType.LAZY)
private List<PlaceholderComponent> placeholderComponents;
#XmlTransient
public List<PlaceholderComponent> getPlaceholderComponents() {
if (placeholderComponents == null)
placeholderComponents = new ArrayList<PlaceholderComponent>();
return placeholderComponents;
}
public void setOrganizationUnits(List<PlaceholderComponent> pPlaceholderComponents) {
placeholderComponents = pPlaceholderComponents;
}
#XmlElement(name = "Component")
public Component getCurrentComponent() {
if (placeholderComponents == null) {
return null;
} else {
PlaceholderComponent placeComp = placeholderComponents.stream()
.filter(pc -> pc.getDateTimeRemoved() == null)
.findFirst()
.orElse(null);
if (placeComp == null) {
return null;
} else {
return placeComp.getComponent();
}
}
}
And in the service there should be two possible calls getUnit & getUnitWithComponents. Now, if I remove the #XmlElement(name = "Component") annotation above getCurrentComponent() and do nothing with the placeholderComponents inside the getUnit call it works as expected, but getUnitWithComponents doesn't work (it works, but doesn't return the components inside the placeholders). When I leave the annotation getUnitWithComponents works as expected, but getUnit gives an error about not being able to lazily load the placeholderComponents as, apparently, JAXB wants to build the Component element even though the whole list isn't called in the service and therefore not loaded.
I can think of 3 possible 'solutions' working around this:
Remove the getCurrentComponent and make a separate call for retrieving the current component in a placeholder which would send a single component XML back
Make two different objects for Placeholder while both are for the same DB-table, using the one for getUnit (where the Component annotation isn't present) and the other for getUnitWithComponents (where the Component annotation is present).
Another option would be splitting into DAO's and DTO's as there might be more of those situations coming, but that splitting would take quite some time by now.
So the main question is: is there a way to get the components inside the unit XML for some calls and leave them out for most of the calls without a workaround? And if not, what solution would you chose? 1, 2, 3 or another one?
I am trying to save an Enum field to database but I am having a problem mapping the field to database. The code I have is as follows:
public enum InvoiceStatus {
PAID,
UNPAID;
}
and I am using this enum in one of my application classes as follows:
public class Invoice {
Enumerated(EnumType.ORDINAL)
#Column(name="INVOICE_STATUS", nullable = false, unique=false)
private InvoiceStatus invoiceStatus;
}
finally I let the app user select the Invoice Status from the view (JSP) using a drop down menu.
But I am not sure how to map the value received from the drop down menu selection to the Invoice Status field
I tried mapping the value received to short as follows, but it won't compile
invoice.setInvoiceStatus(Short.parseShort(request.getParameter("inbStatus")));
can someone please tell me how to map the data received from the view to the enum field?
Enum ordinal values are zero based indexes. In your case:
PAID = 0
UNPAID = 1
So the following code will return PAID:
int invoiceStatus = 0;
invoice.setInvoiceStatus(InvoiceStatus.values()[invoiceStatus]);
And the following code will return UNPAID:
int invoiceStatus = 1;
invoice.setInvoiceStatus(InvoiceStatus.values()[invoiceStatus]);
That means you should be able to do this way:
short invoiceStatus = Short.parseShort(request.getParameter("inbStatus"));
invoice.setInvoiceStatus(InvoiceStatus.values()[invoiceStatus]);
But only if inbStatus is 0 or 1. You should always validate user input for null and invalid values.
I see that u are using
Enumerated(EnumType.ORDINAL)
however after a while it could be quite difficult to troubleshoot if your enum will grow. Another issue with the ordinal is that you could refactor your code and change the order of the enum values and after that you could be in trouble. Mainly if it is a shared codebase and someone just decides to cleanup the code and "group the relevant enum constants together". If you'll use:
Enumerated(EnumType.STRING)
Directly the enum "name" will be inserted into the database. (Therefore you need Varchar type). If you want to present more user friendly version of your enum you could probably have:
public enum InvoiceStatus {
PAID(0, "Paid"), UNPAID(1, "Unpaid"), FAILED(2, "Failed"), PENDING(3, "Pending");
private int st;
private in uiLabel;
private InvoiceStatus(int st, String uiLabel){
this.st = st;
this.uiLabel = uiLabel;
}
private Map<String, InvoiceStatus> uiLabelMap = new HashMap<String, InvoiceStatus> ();
static {
for(InvoiceStatus status : values()) {
uiLableMap.put(status.getUiLabel(), status);
}
}
/** Returns the appropriate enum based on the String representation used in ui forms */
public InvoiceStatus fromUiLabel(String uiLabel) {
return uiLableMap.get(uiLabel); // plus some tweaks (null check or whatever)
}
//
// Same logic for the ORDINAL if you are keen to use it
//
}
Probably this could be also a solution for your problem, however i would really not use the ORDINAL based mapping. But just personal feeling.