Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - How to make JSON date validation?

I have this piece of code:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    protected Date statusDate;

But for somehow it accepts date formats like -

"statusDate": "2017-13-27"

or

"statusDate": "201823-12-12"

Is it possible to validate the format within the request (not manually)?

like image 771
Dvir Avatar asked Sep 16 '25 07:09

Dvir


2 Answers

@JsonFormat is used to set the output format when you're returning the statusDate as response.

It is better you create a DTO object that will accept String statusDate and then convert it to Date format in your controller.

To validate the date in String format, you can use @Pattern

public class StatusDateDto {

    @NotNull(message="Status date is a required field")    
    @Pattern(regexp = "^\\d{4}-\\d{2}-\\d{2}", message="Invalid status date")
    private String statusDate;

    //Getter and setter
}

public ResponseEntity<?> postStatusDate(@Valid @RequestBody StatusDateDto dateDto, BindingResult result) {

        if (result.hasFieldErrors()) {
            String errors = result.getFieldErrors().stream()
                .map(p -> p.getDefaultMessage()).collect(Collectors.joining("\n"));   

            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
        }

        // Convert the String to Date after validation

        return ResponseEntity.ok().build();
    }
like image 91
Olantobi Avatar answered Sep 19 '25 07:09

Olantobi


Yes, you can. Let me show u the details.

First, pls create a base controller to filter all the requests like below:

package com.letv.address.controller;

import com.letv.address.utils.ConstantCode;
import com.letv.address.utils.ResponseWrapper;
import com.letv.xice.core.controller.GlobalController;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by shichaoyang on 2017/1/10.
 */
public class BaseController extends GlobalController {

public ResponseWrapper requestCheckAndPost(BindingResult result) {

    if (result.hasErrors()) {

        List<Object> errorList = new ArrayList<>();

        StringBuilder sBuilder = new StringBuilder();

        for (ObjectError error : result.getAllErrors()) {

            String fieldName = ((FieldError) error).getField();
            String fieldMessage = error.getDefaultMessage();

            sBuilder.append(fieldName)
                    .append(" ")
                    .append(getMessage(fieldMessage))
                    .append(";");

            errorList.add(fieldName);
        }

        return new ResponseWrapper(
                  ConstantCode.FAILING_WITH_ERROR_PARAM_CODE
                , errorList.toArray()
                , ""
                , sBuilder.toString()
                );
    }
    return null;
  }
}

From above code, the BindingResult will check the @JsonFormat or other components header, like @NotBlank, @Pattern and so on. If they hit the rule, they will be caught by the BindingResult and we can get the error. Below is the DTO object I used, just show it to u so that you can get more details:

package com.letv.address.controller.dto;

import com.letv.address.utils.ConstantCode;
import org.hibernate.validator.constraints.NotBlank;

/**
 * Created by shichaoyang on 2016/12/23.
 */
public class ChildrenAreaSelectRequest{

@NotBlank(message = ConstantCode.REQUEST_VALIDATE_NOT_EMPTY)
private String areaIds;

public String getAreaIds() {
    return areaIds;
}

public void setAreaIds(String areaIds) {
    this.areaIds = areaIds;
  }
}

Then in our business logic controller, we need to extend the base controller and write the codes like below:

package com.letv.address.controller;

import com.letv.address.controller.dto.ChildrenAreaSelectRequest;
import com.letv.address.controller.dto.ParentAreaSelectReqeust;
import com.letv.address.domain.Area;
import com.letv.address.service.ChildAreaService;
import com.letv.address.utils.ConstantCode;
import com.letv.address.utils.ResponseWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by shichaoyang on 2016/12/12.
 */
@RestController("areaController")
public class AreaController extends BaseController {

@Autowired
protected ChildAreaService childAreaService;

/**
 * get area info by parent id
 *
 * @param areaReqeust
 * @param result
 */
@ResponseBody
@RequestMapping(value = ConstantCode.CHILD_AREA_PATH, method = {RequestMethod.POST})
public ResponseWrapper childArea(@RequestBody @Valid ParentAreaSelectReqeust areaReqeust, BindingResult result) {

    ResponseWrapper validationWrapper = requestCheckAndPost(result);
    if (validationWrapper != null) {
        return validationWrapper;
    }

    List<Area> areaList = childAreaService.selectByParentId(areaReqeust.getParentId());
    if (areaList == null || areaList.size() == 0) {
        return new ResponseWrapper(ConstantCode.SUCCESS_WITH_EMPTY_DATA_CODE, new ArrayList<>());
    } else {
        return new ResponseWrapper(ConstantCode.SUCCESS_WITH_FILL_DATA_CODE, areaList);
    }
  }
}

By using above method, you can validate the field easily within the request. It's a beautiful way to achive this.

Hope that helps.

EDIT:

Replace the images with real codes so that anyone needs to test it.

like image 42
CharlieShi Avatar answered Sep 19 '25 06:09

CharlieShi