Home > Mobile >  Model contains correct annotation but still passes empty field to the repository - Spring boot, Java
Model contains correct annotation but still passes empty field to the repository - Spring boot, Java

Time:11-10

some strange issue has shown up, in the business model I use list of addresses that cannot be empty or null, but each field in the object address cannot be null or empty either. But when I send a request with one of the fields empty, the request will pass to the repository, which shouldn't happen. Instead of passing a request, the server should return an internal server error.

Address object:

@Data
@NoArgsConstructor
public class Address {
    @NotEmpty(message = "Street may not be empty")
    @Size(min = 2, max = 256)
    private String street;

    @NotEmpty(message = "Number may not be empty")
    @Size(min = 1, max = 5)
    private String number;

    @NotEmpty(message = "Postal code may not be empty")
    @Field("postal_code")
    @JsonProperty("postal_code")
    @Size(min = 5, max = 6)
    private String postalCode;

    @NotEmpty(message = "City may not be empty")
    @Size(min = 2, max = 256)
    private String city;

    @NotEmpty(message = "Province may not be empty")
    @Size(min = 2, max = 256)
    private String province;

    @NotEmpty(message = "Country may not be empty")
    @Size(min = 2, max = 256)
    private String country;
}

Business object which contains list of addresses:

@Data
@NoArgsConstructor
@Document(collection = "businesses")
public class Business {
    @Id
    private String id;

    @NotBlank
    @Size(max = 64)
    private String name;

    @Field("created_at")
    private Date createdAt;

    @Field("updated_at")
    private Date updatedAt;

    private Boolean active;

    @DBRef
    private User owner;

    private List<Address> addresses;

    public Business(String name, User owner, List<Address> addresses, Date createdAt, Date updatedAt, Boolean active) {
        this.name = name;
        this.owner = owner;
        this.addresses = addresses;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
        this.active = active;
    }

    public Business(String name, User owner, List<Address> addresses, Date updatedAt, Boolean active) {
        this.name = name;
        this.owner = owner;
        this.addresses = addresses;
        this.updatedAt = updatedAt;
        this.active = active;
    }
}

And in the end, service:

@Override
public ResponseEntity<?> createBusiness(CreateBusinessRequest request, String token) throws RuntimeException {
    Optional<User> user = userRepository.findByUsername(jwtUtils.getUserNameFromJwtToken(token.substring(7)));
    if(businessRepository.existsByName(request.getName())) {
        throw new ItemAlreadyExistsException("Business with "   request.getName()   " already exists!");
    }

    if(user.isEmpty()) {
        throw new NotFoundException("User with "  user.get().getUsername()  " does not exist!");
    }

    if(request.getAddresses().isEmpty() || request.getAddresses() == null) {
        throw new InvalidInputException("Address is empty!");
    }

    Business business = new Business(
            request.getName(),
            user.get(),
            request.getAddresses(),
            new Date(),
            new Date(),
            true
    );

    businessRepository.save(business);
    return ResponseEntity.ok(business);
}

Controller:

@PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')")
@PostMapping("/create")
public ResponseEntity<?> createBusiness(@Valid @RequestBody CreateBusinessRequest request, @RequestHeader (name="Authorization") String token) {
    return businessService.createBusiness(request, token);
}

Request:

{
    "name": "Test business",
    "addresses": [
        {
            "street": "",
            "number": "100",
            "postal_code": "84104",
            "city": "Test city",
            "province": "Test",
            "country": "Slovakia"
        }
    ]
}

I hope that I explained my issue correctly. Is there any solution to this issue?

Thanks in advance.

CodePudding user response:

Per this question I recommend adding the @Valid annotation (javax.validation.Valid) to the addresses property of the Business class. Also see the example here

CodePudding user response:

My guess is that you are missing one key dependency:

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-validation</artifactId> 
</dependency>

CodePudding user response:

To fully configure method level security you need to add the following annotation/class:

@Configuration
@EnableGlobalMethodSecurity(
  prePostEnabled = true, 
  securedEnabled = true, 
  jsr250Enabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}

This will turn on validation of your service methods. As mentioned earlier, you can add BindingResult to your controller and check for errors in the controller if needed.

  • Related