I am trying to map a json object to a Spring boot model class now the contract says for a property it have only a certain set of allowed values(not more than 3).
Example:
Suppose that json has field "name" and the contract says allowed values for field "name" are john,todd,phil
Anything other than john,todd,phil wont be accepted.
Is there any way to achive this constraint using any annotations
You can use following solutions
Solution 1:
Using #Pattern annotation with regex , if you want to use case insensitive use appropriate flags
#Pattern(regexp = "john|todd|phil", flags = Pattern.Flag.CASE_INSENSITIVE)
Solution 2:
By creating a enum class type with allowed values
public enum {
JOHN, TODD, PHIL
}
In your model class use #Enumerated(EnumType.STRING) on name filed
Related
I have defined two Spring boot REST resources
POST /customer
The above resource is for adding a customer with the below JSON as a request
{
"customerFirstName" : "John"
"customerLastName" : "Doe"
"customerAddress" : {
"addressLine1" : "22 XYZ Drive"
"addressLine1" : "22 suite"
"state" : "PY"
"country" : "Ind"
"zipCode" : "1235312"
}
}
Now I need to implement update the customer info, so the below resource is defined. The requirement is any information related to customers can be updated. So the Input JSON in case of an update is the same as in the case of add request. The only caveat the information that is not provided will not be updated. Only information that is provided will be updated.
PUT /customer/{customerId}
Question : I want to use Spring boot Bean request validation. However, the validation requirements are different for adding and updating resources, so not able to use the same Customer domain model. However, the domain model in both cases is exactly the same so this is causing a code duplication. How can I avoid that or is it correct to move the validation outside and code.
Example : In the case of adding a customer it is mandatory to provide a customer address, so one can use annotation like #NotNull. However, in the case of updating the customer, the customer address is not mandatory.
You should be able to use validation groups and keep a single model class. Each constraint has groups attribute that you can use to define a validation scheme. You can have a Create group that you'll use only in the POST request and ignore in the PATCH one:
interface Create {}
class Customer {
#NotNull(groups = Create.class)
private String firstName;
#NotNull(groups = Create.class)
private String lastName;
//....
}
And then as you are using Spring you'd want to take a look at #Validated annotation. This one allows you to define the particular groups you want to validate against:
#PostMapping("/customer")
public ResponseEntity<Customer> create(#RequestBody #Validated(Create.class) Customer customer) {
// do your thing
}
You can also check this part of the documentation to learn more about groups and their capabilities
I want to create a StudentApiController annotation for RequestMapping. It needs to add auto prefix for the RequestMapping.
Example usage 1:
#StudentApiController(value="/payment")
class PaymentEndpoint
mapping value needs to be "/student/payment"
Example usage 2:
#StudentApiController(value="/exam")
class ExamEndpoint
mapping value needs to be "/student/exam"
This is my code:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#RequestMapping
annotation class StudentApiController(
val value: String = "",
#get:AliasFor(annotation = RequestMapping::class, attribute = "value")
val aliasValue: String = "/student" + value
)
I am getting this error:
Default value of annotation parameter must be a compile-time constant
Are you expecting all your endpoints to start with /student?
If yes then you can use spring.mvc.servlet.path=/student or server.servlet.context-path=/student property in your application.properties.
If not then may be you can add logic in interceptor to prefix annotation value provided through your annotation. I haven't tried this for prefixing something in preHandle(), but I have tried it for postHandle() and it works.
Refer this link it appends thymeleaf's custom layout using custom annotation through interceptor. You can implement same logic for your requirement.
Edit 1
You may refer this answer which provides another approach/es to handle your requirement.
I have a users table and I am trying to use annotated Queries in spring boot to get a result set. I am able to get result set as a list, but that does not have field names. How do I get the result set with field name as key and value pairs?
Current response [[1,"Jay"]] , what I want to do is {"id":1,"Name":"Jay"}
-----Here is my repository class-----
#Repository
public interface UsersauthRepository2 extends JpaRepository<Users2,Long> {
#Query("select id,name,email from Users u where LOWER(email) = LOWER(:email) and LOWER(u.password) = LOWER(:password)")
List<Users2> querybyemail(#Param("email") String email,#Param("password") String password);
}
The request doesn't return fields names.
If you need to get them :
You have them already as method argument
You need to use reflection.
Good luck
I am trying to implement partial validation in Spring Webflow 2.4. According to their reference manual the validation should be done very simply using groups:
#NotNull
#Size(min = 2, max = 30, groups = State1.class)
private String name;
In my understanding the State1 should be the ID of view-state in which the model should be validated. So the definition of this view state in flow.xml would look like this:
<view-state id="state1" model="modelObject"/>
I was trying to define the State1 as an inner class of my model object, but without success.
The Webflow reference doesn't provide full manual for partial validation, so my question is: Am I missing something? Does anybody have experience with using the partial validation using JSR303 groups?
Thanks, Shimon
I think I can answer my own question now :)
The root of the problem was in 2 things:
The Group1 should be an inner interface of model object. So the model object class should look something like this:
public clas ModelObject{
#NotEmpty(groups=Group1.class)
private String field1;
public interface Group1{}
}
the name od validation-hint should be in single quotes
validation-hints="'group1'"
"In my understanding the State1 should be the ID of view-state in which the model should be validated."
Here groups is not referring to view-state id. It is an inner class or parent or interface implemented by model object.
To realize JSR-303 partial validations, in SWF 2.4 onwards(this is the version SWF starts supporting it), you need to specify validation-hints as:
<view-state id="someView" model="modelObject" validation-hints="group1,group2">
where group1, group2 can be inner Class either in the model type modelObject or its parent types or interfaces implemented by modelObject.
As per the documentation here:
Each hint can be an inner Class either in the model type or its parent types.
For example, given org.example.MyModel with inner type Group1 and Group2 you
can specify the hints "group1", "group2" or both "group1,group2". A hint can
also be a fully qualified class name. The hint "default" indicates the default
validation group, i.e. javax.validation.groups.Default. Also, the validation-hints
property can be an expression that resolves to a String or an Object[] containing
Class based hints.
What I'm trying to accomplish is:
Have a bean backed form being validated, for example using the following class
public class PersonForm {
#NotNull
String name;
List<Long> interests;
// This attribute is not filled out in the form
List<Interest> realInterests;
}
So, "name" and "interests" come from the web form. "name" has some constrains (NotNull) and using #Valid does what it is supposed to do.
"interests" is a list of Interest ids.
After doing the initial validation of the "name" I fill out the List collection.
#CustomValidInterest
public class Interest {
Long id;
String name;
boolean available;
}
I want to validate this structure afterwards. "#CustomValidInterest" is a custom validation annotation.
I can do a 2-stage validation using do this with Validation Groups.
The problem is, if some "Interest" object is not valid I want to associate the error message with the "interests" field (List< Long > type), so when I retrieve the form errors the error is associated with the right field.
Maybe I'm trying to use validation the wrong way. I was trying to avoid having a bunch of programmatic comparisons which filled errors manually.
Answering my own question, this is achievable using PropertyEditors. The form might return a List< Long > but the form object can have only a List < Interest > which is built using said Property mapper. After that a #Valid on that list should validate any constraints that "Interest" enforces.