Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design patterns - How to enforce object attributes only in some situations (Builder pattern, Dependency Injection)

I am in a very particular situation with one of the classes I'm coding. I have this class called User that looks like this:

public class User {
    private long id; // + getters and setters
    private boolean isDeletable; // + getters and setters
    private String name; // + getters and setters
    private String password; // + getters and setters
    private String email; // + getters and setters
    private String authenticationRealm; // + getters and setters
    private String displayName; // + getters and setters
    private Date deletedDate; // + getters and setters
}

Within my code there are several situations where I just need an empty object of the type User and therefore just build it using the default constructor: new User().

However, I have another class called CreateUserRequest which models a REST request to create the user in a server. The minimum payload must contain the name, password, email, and authenticationRealm attributes sent in JSON format.

Right now I am handling this by checking for these parameters in the constructor of the request:

public CreateUserRequest(User user) {
    if(user.getName() == null || user.getPassword() == null || user.getEmail() == null || user.getAuthenticationRealm() == null)
        throw new RuntimeException("Not enough attributes in User object. Minimum: name, password, e-mail and authentication realm.");
}

This is working OK but something is itchy... I would like to enforce this in a safer way, so that the code would enforce the attributes to be populated with no possibility of an exception being thrown.

I feel like there must be a better way to do this with a design pattern. I thought of creating a UserRequestBuilder class, but that would also possibly imply throwing an exception in the build() method (otherwise, is there a way I can guarantee that the attributes are populated before build()?). Dependency injection also sounds like a possibility, but I'm not sure how I would put it in place in this particular example...

Any thoughts?

like image 892
MisterStrickland Avatar asked Mar 22 '16 15:03

MisterStrickland


People also ask

Which design pattern ensures that only one object of particular class gets created?

The Singleton Design Pattern is a Creational pattern, whose objective is to create only one instance of a class and to provide only one global access point to that object.

Is StringBuilder a Builder pattern?

In Java, the builder design pattern is used in the StringBuilder class. StringBuilder contains the append() method to construct string step-by-step, and finally, we call the toString() method to get the constructed string object. StringBuilder builder = new StringBuilder(); String message = builder .

What does Builder () build () do?

It returns the builder itself, so that the setter calls can be chained, as in the above example. In the builder: A build() method which calls the method, passing in each field. It returns the same type that the target returns.

Which design pattern can be used to modify the functionality of an object at runtime explain with a suitable scenario?

Decorator Pattern The decorator design pattern is used to modify the functionality of an object at runtime. At the same time, other instances of the same class will not be affected by this, so individual object gets the modified behavior.


1 Answers

How about making your REST services operate on a UserDTO? (Off course, the UserDTO could be replaced with a subclass of User).

You could annotate the fields, setters or constructor parameters on the UserDTO with @NonNull and have the Checker Framework issue compiler warnings when passing null values instead of name password, email etc to the UserDTO.

Using a framework like Mapstruct, mapping between the REST services DTOs and the backend objects is very easy:

@Mapper
public interface UserMapper {

    public static final UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    UserDTO map(User user);

    User map(UserDTO userDTO);
}

Above code will upon compilation generate a UserMapper implementation, with autogenerated code for the specified methods ( - and the autogenerated code simply pairs similarly named getters and setters. You could do this yourself, but with many DTOs/Entities is becomes time consuming and boring).

In the DTOs you could exclude all those fields you do not want to expose.

Ps. My own usage of above mentioned is this: I am creating a REST server based on Jersey, i.e. the reference implementation of JAX-RS. This project, call it A, only knows about the DTOs. The REST methods calls into another project B, which retrieves the objects from database, and maps them to the corresponding DTO, which is then returned to project A. Part of the reason for this pattern is that the entities of project B for historical reasons are cluttered with methods/functionality, which should not be exposed to project A. As for the sanity checks (JSON to DTO), jersey supports Bean Validation, which is to say, that the framework will validate each rest resource's input beans if they are annotated with @Valid. It is also possible to create your own custom annotations, which have a ConstraintValidator defined. The bean validation framework will check these constraints on the annotated jersey REST method parameters. See https://jersey.java.net/documentation/latest/bean-validation.html#d0e13690

like image 63
Hervian Avatar answered Sep 18 '22 13:09

Hervian