I want to code a REST API that is multileveled like:
/country
/country/state/
/country/state/{Virginia}
/country/state/Virginia/city
/country/state/Virginia/city/Richmond
I have a single java class that is a Country resource with #Path("country")
How do I create a StateResource.java and CityResource.java so that my Countryresource can use the StateResource in the way I am planning to use it? Any useful links on how to construct this kind of thing in Java?
The CountryResource class needs to have a method annotated with the #Path to the sub-resource CityResource. By default, you are responsible for creating the instance of CityResource e.g.
#Path("country/state/{stateName}")
class CountryResouce {
#PathParam("stateName")
private String stateName;
#Path("city/{cityName}")
public CityResource city(#PathParam("cityName") String cityName) {
State state = getStateByName(stateName);
City city = state.getCityByName(cityName);
return new CityResource(city);
}
}
class CityResource {
private City city;
public CityResource(City city) {
this.city = city;
}
#GET
public Response get() {
// Replace with whatever you would normally do to represent this resource
// using the City object as needed
return Response.ok().build();
}
}
CityResource provides the methods that handle the HTTP verbs (GET in this case).
You should look at the Jersey documentation regarding sub-resource locators for more info.
Also note that Jersey provides a ResourceContext to get it to instantiate the sub-resource. If you're going to use #PathParam or #QueryParam in the sub-resource I believe you need to use this as the runtime doesn't touch sub-resources when created yourself via new.
Related
I would like to create a C# like composite class action with spring boot 2 with an array request.
My client will send the following:
Contet-Type: application/x-www-form-urlencoded
With body:
company[name]:qwe
company[size]:1
address[country]:asd
address[address]:zxc
My action should be something like this:
#PostMapping
public ResponseEntity<ResponseData<String>> action(CompanyCompositeRequest request)
{
...
}
And the classes that I'd like to fill automatically:
class CompanyCompositeRequest {
private Company company;
private Address address;
}
class Company {
private String name;
private int size;
}
class Address {
private String country;
private String address;
}
And I'd like to run the Validator from the javax.validation on the properties of the classes in the composite.
Is that even possible? I tried a lot of version, and didn't find a working version, but I saw similar solutions. If I need to change the sent data from the client it's possible, for example in a JSON raw data, or something like that.
Thanks!
It is possible by using the #RequestBody annotation in your controller method. It will make Spring automagically map the request body into your custom class.
See: http://websystique.com/springmvc/spring-mvc-requestbody-responsebody-example
I'm working on a rest api project with spring boot and hibernate, and I'm wondering on json serialization of RestController using Jackson.
Here is the problem: I use external hibernate entities class defined in a library I cannot edit. This classes are very complex and define lot of field I'm not interested in when I return the object with the rest api.
Actually, I've solved the problem wrapping the original class with a wrapper class that exposes only the values I want to return from the controller.
Eg:
original class
class AccountEntity {
///...
public String getName() {
return this.name;
}
/// ... Lot of code here
}
Wrapper class:
class AccountWrapper {
AccountEntity original;
public AccountWrapper(AccountEntity original) {
this.original = original;
}
public String getName() {
return this.original.getName();
}
}
and the use the Wrapper as following
#RestController("/api/user")
public class UsersController {
#GetMapping("/")
public AccountWrapper getUser() {
AccountEntity account = //get account in some way
AccountWrapper accountWrapper = new AccountWrapper(account);
return accountWrapper;
}
}
The method works well, but it's not very clean and makes stuff more complex (e.g., when I have to return lists), because I always have to wrap the original class.
I didn't found a method to make me able to specify which fields I want to serialize without modify (and I cannot) the original class.
Any help?
Instead of using a wrapper class, create a DTO object for the rest API that will be leaner than the DB entity and a trasformer to create DTO from entity (and vice a verce)
The difference from using a wrapper here is that the DB entity is not part of the DTO, and thus does not need to be serialized on the response.
The big advantage here is that you separate the DB layer from the API layer, which makes it more flexible and easy to manage.
you can read more about this pattern here
Apparently, you can use Jackson Mixins to annotate a class with Jackson annotations.
See this answer for example.
The idea is to create an class with the annotations you want and to use objectMapper.getSerializationConfig().addMixInAnnotations() to register the MixIn with your class.
For example:
//Class you don't controll
public class User {
private String name;
private String password; //attribute we want to omit
//... getters and setters
}
public abstract class UserMixIn {
#JsonIgnore String getPassword();
}
objectMapper.addMixInAnnotations(User.class, UserMixIn.class);
Hope it helps,
Consider the following pojo for reference:
public class User{
private String username;
private String firstName;
private String middleName;
private String lastName;
private String phone;
//getters and setters
}
My application is a basically spring-boot based REST API which exposes two endpoints, one to create the user and the other to retrieve a user.
The "users" fall into certain categories, group-a, group-b etc. which I get from the headers of the post request.
I need to validated the user data in runtime and the validations may differ based on the group of a user.
for example, the users that fall into group-a may have phone numbers as an optional field whereas it might be a mandatory field for some other group.
The regex may also vary based on their groups.
I need to be able to configure spring, to somehow dynamically validate my pojo as soon as they are created and their respective set of validations get triggered based on their groups.
Maybe I can create a yml/xml configuration which would allow me to enable this?
I would prefer to not annotate my private String phone with #NotNull and #Pattern.
My configuration is as follows:
public class NotNullValidator implements Validator {
private String group;
private Object target;
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
#Override
public void validate(Object o) {
if (Objects.nonNull(o)) {
throw new RuntimeException("Target is null");
}
}
}
public interface Validator {
void validate(Object o);
}
#ConfigurationProperties(prefix = "not-null")
#Component
public class NotNullValidators {
List<NotNullValidator> validators;
public List<NotNullValidator> getValidators() {
return validators;
}
public void setValidators(List<NotNullValidator> validators) {
this.validators = validators;
}
}
application.yml
not-null:
validators:
-
group: group-a
target: user.username
-
group: group-b
target: user.phone
I want to configure my application to somehow allow the validators to pick their targets (the actual objects, not the strings mentioned in the yml), and invoke their respective public void validate(Object o) on their targets.
P.S.
Please feel free to edit the question to make it better.
I am using jackson for serializing and deserializing JSON.
The easiest solution to your problem, as i see it, is not with Spring or the POJOs themselves but with a design pattern.
The problem you're describing is easily solved by a strategy pattern solution.
You match the strategy to use by the header you're expecting in the request, that describes the type of user, and then you perform said validations inside the strategy itself.
This will allow you to use the same POJO for the whole approach, and deal with the specifics of handling/parsing and validating data according to the each type of user's strategy.
Here's a link from wiki books with a detailed explanation of the pattern
Strategy Pattern
Suppose you have a basic interface for your strategies:
interface Strategy {
boolean validate(User user);
}
And you have 2 different implementations for the 2 different types of user:
public class StrategyA implements Strategy {
public boolean validate(User user){
return user.getUsername().isEmpty();
}
}
public class StrategyB implements Strategy {
public boolean validate(User user){
return user.getPhone().isEmpty();
}
}
You add a Strategy attribute to your User POJO and assign the right implementation of the Strategy to that attribute when you receive the post request.
Everytime you need to validate data for that user you just have to invoke the validate method of the assigned strategy.
If each User can fit multiple strategies, you can add a List<Strategy> as an attribute instead of a single one.
If you don't want to change the POJO you have to check which is the correct strategy every time you receive a post request.
Besides the validate method you can add methods to handle data, specific to each strategy.
Hope this helps.
You can use validation groups to control which type of user which field gets validated for. For example:
#NotBlank(groups = {GroupB.class})
private String phone;
#NotBlank(groups = {GroupA.class, GroupB.class})
private String username;
Then you use the headers from the request that you mentioned to decide which group to validate against.
See http://blog.codeleak.pl/2014/08/validation-groups-in-spring-mvc.html?m=1 for a complete example.
Updated to include a more comprehensive example:
public class Val {
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
public boolean isValid(User user, String userType) {
usergroups userGroup = usergroups.valueOf(userType);
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user, userGroup.getValidationClass());
return constraintViolations.isEmpty();
}
public interface GroupA {}
public interface GroupB {}
public enum usergroups {
a(GroupA.class),
b(GroupB.class);
private final Class clazz;
usergroups(Class clazz) {
this.clazz = clazz;
}
public Class getValidationClass() {
return clazz;
}
}
}
This doesn't use application.yaml, instead the mapping of which fields are validated for each group is set in annotations, similar results using Spring's built in validation support.
I was able to solve my problem with the use of Jayway JsonPath.
My solution goes as follows:
Add a filter to your API which has the capability to cache the InputStream of the ServletRequest since it can be read only once. To achieve this, follow this link.
Create a bunch of validators and configure them in your application.yml file with the help of #ConfigurationProperties. To achieve this, follow this link
Create a wrapper which would contain all your validators as a list and initialize it with #ConfigurationProperties and the following configuration:
validators:
regexValidators:
-
target: $.userProfile.lastName
pattern: '[A-Za-z]{0,12}'
group: group-b
minMaxValidators:
-
target: $.userProfile.age
min: 18
max: 50
group: group-b
Call the validate method in this wrapper with the group which comes in the header, and then call the validate of the individual validators. To achieve this, I wrote the following piece of code in my wrapper:
public void validate(String input, String group) {
regexValidators.stream()
.filter(validator -> group.equals(validator.getGroup()))
.forEach(validator -> validator.validate(input));
minMaxValidators.stream()
.filter(validator -> group.equals(validator.getGroup()))
.forEach(validator -> validator.validate(input));
}
and the following method in my validator:
public void validate(String input) {
String data = JsonPath.parse(input).read(target);
if (data == null) {
throw new ValidationException("Target: " + target + " is NULL");
}
Matcher matcher = rule.matcher(data);
if (!matcher.matches()) {
throw new ValidationException("Target: " + target + " does not match the pattern: " + pattern);
}
}
I have created a functioning project to demonstrate the validations and it can be found here.
I understand that the answer alone might not be very clear, please follow the above mentioned url for the complete source code.
Is there a way to set resource relations through annotations? I made a similar question a some time ago but i've not been clear enough. I want to have something like this:
public class UserResource {
private String username;
#Relation(value = "{servicebaseUrl}/classes/${value}", rel = "class")
private String classId;
// Getters and setters
}
And then add a message converter which would add links only if client sends Accept = application/hal+json, avoiding the fact of doing two different controller endpoints for application/hal+json and application/json. Does Spring offers something like that? I found that it actually offers this #Relation annotation(or similar one) but it seems that it is not for the same purposes.
No this is not possible - you would have to implement a ResourceAssembler to add links to your resources.
Usually your resources extend ResourceSupport.
class PersonResource extends ResourceSupport {
String firstname;
String lastname;
}
Then your create ResourceAssembler to control the creation of that resource:
class PersonResourceAssembler extends ResourceAssemblerSupport<Person, PersonResource> {
public PersonResourceAssembler() {
super(PersonController.class, PersonResource.class);
}
#Override
public PersonResource toResource(Person person) {
PersonResource resource = createResource(person);
// … do further mapping and add links
resource.add(new Link("http://myhost/people"));
return resource;
}
}
See the spring hateoas documentation for details
I have the following JAX-RS resource:
#POST
public Response createPerson(
final User user) {
...
}
and User bean is:
public class User {
protected String lastName;
protected String role;
#DefaultValue("true")
protected Boolean active;
#DefaultValue("dd.MM.yyyy")
protected String dateFormat;
...//getters and setters
}
When I don't specify values for 'active' and 'dateFormat' I expect them to be filled with default values. But they are null.
I've read docs for #DefaultValue and it seems to be not suitable for my scenario. But how can I ask jersey to fill these absent properties wiith defaults?
Edit:
I want to use annotations instead of the code (e.g. in constructor) because I want to be able to automatically generate API documentation (e.g. swagger). Swagger already supports #DefaultValue when providing parameter info, but I can extend it, if another approach with annotations is used.
Of course I can use code together with swagger-specific annotations, but this leads to duplications. I'd rather use same meta-info to get both application logic and documentation. I'm ok with custom annotations, while extending both jersey and swagger.
You could set the defaults either directly in the class definition or in the no-arg constructor, all in plain old java, no need for any annotations. When using the primitive type instead of the wrapper, active would default to false.
Just as an example:
public static class User {
public boolean primActive;
public Boolean wrapActive;
public boolean consActive;
public User() {
consActive = true;
}
}
The resource:
#POST
#Path("foo")
public User getUser( User user ) {
return user;
}
When posting an empty request (when using json: {}), the following is returned.
{
primActive: false
consActive: true
}