Skip to content

Instantly share code, notes, and snippets.

@mzakyalvan
Last active July 4, 2018 09:26
Show Gist options
  • Save mzakyalvan/a2a24b14ff0f834b8f8f64d00a6965f7 to your computer and use it in GitHub Desktop.
Save mzakyalvan/a2a24b14ff0f834b8f8f64d00a6965f7 to your computer and use it in GitHub Desktop.

Notes

Ignore Files

No need to include target build directory into scm commit. Check them into scm can cause bigger repo size, drive longer time to check out fresh project copy.

Some IDE specific project (.idea directory or *.iml files) configuration might cause problems on other computers, for example file path incompatibility. Following .gitignore is enough for each module.

/target/
!.mvn/wrapper/maven-wrapper.jar

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

pom.xml

Use Latest Spring Boot Patch Release

Use latest spring boot version. In time of writing, latest version is 1.5.14.RELEASE. The reason is, since used version 1.5.8.RELEASE there are many important patches and improvements. Please remember, just update version of reactor's parent project version.

Use Consistent Spring Version

If you already defined reactor parent project as following

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!-- omitted -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.8.RELEASE</version>
    </parent>
    <!-- omitted -->
</project>

Then use consistent version of spring framework version in all of modules. For example, spring boot 1.5.x using spring framework 4.3.x.RELEASE not 5.0.x.RELEASE). Look at pom.xml of rest-web-model and entity modules, this modules use spring-web artifact with version 5.0.4.RELEASE. This might lead to hard to trace errors in runtime.

Other note, no need to declare spring boot starter modules in dependencyManagement of project reactor, because when we use spring-boot-starter-parent as parent of project, all spring boot starters and some dependencies (e.g. jackson-databind etc) already declared there.

Validate, Validate, Validate

For more detailed sample, look at this sample project.

Bean validation constraint annotations (@NotNull, NotBlank, @Valid, @Size etc) must be declared in pojo property. Bean validation artifact (and Hibernate Validator as default implementation) transitively imported by org.springframework.boot:spring-boot-starter-web. If don't use that web starter in your project or module (direct or transitive), you have to add them manually into your project, in case spring-boot 1.5.x-RELEASE, add following dependency (Don't use 6.x.x release).

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.3.6.Final</version>
</dependency>

Validate @RequestBody Hander Parameter.

Validate input data from outer most components.

Following snippet copied from rest-web module.

public ResponseEntity<?> addAnEvent(@RequestBody EventsDataRequest eventsDataRequest, @RequestParam String indexName)  {}

We can improve by using internal spring webmvc supports for web request data binding and validation as following snippet.

This might help us in guard against null pointer exception.

public ResponseEntity<?> addAnEvent(@RequestParam String indexName, @Validated @RequestBody EventsDataRequest eventsData, BindingResult bindings)  {
  if(binding.hasErrors()) {
    Object errorBody = buildErrorBody();
    return ResponseEntity.badRequest().body(errorBody).build();
  }

  // ... continue...
}

You can use @javax.validation.Valid, but you can't give validation group hint with this annotation.

If you need to add custom validation logic, for example by calling any service method

public ResponseEntity<?> addAnEvent(@RequestParam String indexName, @Validated @RequestBody EventsDataRequest eventsData, BindingResult bindings)  {
  if(!bindings.hasFieldErrors("sampleProperty") && sampleService.booleanCheck(eventsData.getSampleProperty())) {
    bindings.rejectValue("sampleProperty", "sampleProperty.error", "Sample property error");
  }

  if(binding.hasErrors()) {
    Object errorBody = buildErrorBody();
    return ResponseEntity.badRequest().body(errorBody).build();
  }

  // ... continue...
}

Or implement org.springframework.validation.SmartValidator type to extends validation based on your business cases.

Method Parameter Validation

Declare org.springframework.validation.beanvalidation.MethodValidationPostProcessor as spring bean in your application. Then you can use javax.validation constraints (e.g. @Valid, @NotNull, @NotBlank etc) on your service method parameter. For example :

// Contract
public interface SampleService {
  // Mark with constraints on contract method arguments.
  public Single<ResultType> doOperation(@NotBlank String firstParameter, @Valid @NotNull InputObject secondParameter);
}

// Implementation.
@Service
@Validated // Instruct spring plumbing to do method argument validation on runtime (Proxy ob this type enchanced by MethodValidationPostProcessor).
class SampleServiceImpl {
  public Single<ResultType> doOperation(String firstParameter, InputObject secondParameter) {
    // return ...
  }
}

You can also use your custom created validation constraints.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment