8

I am using Spring 4.1.4 and implementing a simple REST service. I do have a POST method which gets a Person object as request.

@ResponseStatus(value = HttpStatus.CREATED)
@RequestMapping(value = "", method = RequestMethod.POST, headers = "Accept=application/json", consumes = "application/json")
public void add(@Valid @RequestBody Person oPerson) throws Exception {
    //do the things
}

Bean:

public class Person {

    public Person(){ }

    private String firstname;

    private String lastname;

    private Integer activeState;

    //getter+setter
}

My question is - is there a possibility to set a default value for the properties in the bean. Something like this:

@Value(default=7)
private Integer activeState;

I know when using the @RequestParam annotation in a @RestController methode it is possible to set a default value with @RequestParam(value="activeState", required=false, defaultValue="2") but is there a possibility to do a similar thing on class level?

Arpit Aggarwal
  • 27,626
  • 16
  • 90
  • 108
K.E.
  • 818
  • 2
  • 12
  • 28
  • when should the default value been applied: if the parameter is not in the request at all, of if the parameter is null/empty? – Ralph Feb 19 '16 at 07:24
  • 1
    Simply just declare a value for the integer field in the class: `private Integer activeState = 2;` Or did I misunderstand you? – Robin Jonsson Feb 19 '16 at 07:24
  • @Ralph good question - in both cases: not present and null or empty – K.E. Feb 19 '16 at 07:25
  • @RobinJonsson - I also thought about that, but I don't know if that is the best solution, I use the object also as a persistence object for a database... – K.E. Feb 19 '16 at 07:28
  • @K.E. I've always had the mindset of not using my entities all the way to the front-end. However, setting the default value like this works as long as the incoming object hasn't overwritten that field. Isn't that what you were looking for? – Robin Jonsson Feb 19 '16 at 07:30
  • @RobinJonsson yes, you are right with the entities which shouldn't be used but in this specific case it is ok for me. And ok, you persuaded me - if you post this solution as answer, i will accept. – K.E. Feb 19 '16 at 07:35
  • Or just add a method annotated with `@ModelAttribute` which constructs a `Person` object and sets the default values. That way you only have defaults in the web layer and not tied into your `Person` object. – M. Deinum Feb 19 '16 at 07:44

2 Answers2

17

Your Person class is not really a spring bean. It is simply a class whose parameters are set when you make a call to your application endpoint due to the @RequestBody annotation. The parameters which are not in the body of your call will simply not get binded so to solve your problem you can do this:

  1. Set default values for your person class like this (toString() is overridden for convenience:

    public class Person {
    
        public Person() {
        }
    
        private String firstName = "default";
        private String lastName = "default";
        private Integer activeState = 7;
    
        public String getFirstName() {
            return firstName;
        }
    
        public String getLastName() {
            return lastName;
        }
    
        public Integer getActiveState() {
            return activeState;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "firstName='" + firstName + '\'' +
                    ", lastName='" + lastName + '\'' +
                    ", activeState=" + activeState +
                    '}';
        }
    }
    
  2. Perform the request to your endpoint, for example with this json data:

    {
        "firstName": "notDefault"
    }
    
  3. If you print out the person object in your controller, you'll notice that the firstName got the non-default value while others are default:

    public void add(@Valid @RequestBody Person oPerson) {
        System.out.println(oPerson);
    }
    

Console output: Person{firstName='notDefault', lastName='default', activeState=7}

Edd
  • 1,982
  • 2
  • 21
  • 29
  • Great, and what if your dto's are immutable? Also I don't believe it's the responsibility of dto object to dictate the behavior or controller endpoint – Ben Aug 28 '19 at 07:12
  • @Ben if they're immutable, then handle default value assignment in the controller method. That is, check which values are missing and make a new copy of your immutable object with them being assigned. – Edd Sep 24 '19 at 21:12
  • This is not a good case when we have the same DTO for multiple endpoints. Some endpoints would like to have different default values or no default values at all. – Praytic Sep 16 '21 at 13:09
-1

Adding to @Edd answer, if you want to override the default values from the input, then we have to annotate the bean with @JsonAutoDetect, as follows:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;

@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
public class Person {

    public Person() {
    }

    private String firstName = "default";
    private String lastName = "default";
    private Integer activeState = 7;

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Integer getActiveState() {
        return activeState;
    }

    @Override
    public String toString() {
        return "Person{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", activeState=" + activeState +
                '}';
    }
}
Arpit Aggarwal
  • 27,626
  • 16
  • 90
  • 108