简体   繁体   中英

How to Avoid Java Generics Warnings in Factory Pattern

I want to implement generic validator to validate business rules in my service layer with using Factory Design Pattern and adding some kinda rule chaining like Rules Engine. I have working solution which I'm not sure if it is the best way to do.

Here is my question: I want to ensure type safety in the compile time rather than having/checking class types in runtime. So it will make developer safe to use method without having chance of ClassCastException. Here is the last warning I want to solve but couldn't make it so far, I need some help and open for the advice If something is not clear in my design:

Unchecked call to 'validate(T)' as a member of raw type '...Validator'

Lines I get the warning:

Validator validator = assignedSelectionValidatorFactory.createValidator(ValidationMode.SAVE);
validator.validate(new AssignedSelectionValidatable(assignSelectionRequestDto));

Here is my factory interface

public interface ValidatorFactory {

    /**
     * Creates factory which returns {@link Validator} based on the {@link ValidationMode}
     */
    Validator createValidator(ValidationMode validationMode);
}

Here is my concrete implementation of the factory

@Component
public class AssignedSelectionValidatorFactory implements ValidatorFactory {

    private AssignedSelectionSaveValidator assignedSelectionSaveValidator;

    public AssignedSelectionValidatorFactory(AssignedSelectionSaveValidator assignedSelectionSaveValidator) {
        this.assignedSelectionSaveValidator = assignedSelectionSaveValidator;
    }

    @Override
    public Validator createValidator(ValidationMode validationMode) {
        switch (validationMode) {
            case SAVE:
                return assignedSelectionSaveValidator;
            default:
                return null;
        }
    }
}

Here is the Validator interface

public interface Validator<T extends Validatable> {

    /**
     * Validates each validation rules
     */
    void validate(T objectsToValidate);

}

Here is the concrete implementation of Validator interface. This calls validation rules in its implementation

@Component
public class AssignedSelectionSaveValidator implements Validator<AssignedSelectionValidatable> {

    private AssignedSelectionUniqueRule assignedSelectionUniqueRule;

    AssignedSelectionSaveValidator(AssignedSelectionUniqueRule assignedSelectionUniqueRule) {
        this.assignedSelectionUniqueRule = assignedSelectionUniqueRule;
    }

    @Override
    public void validate(AssignedSelectionValidatable assignedSelectionValidatable) {
        assignedSelectionUniqueRule.apply(assignedSelectionValidatable.getAssignSelectionRequestDto());
    }

}

And here is the validation rule. Each validation rule is independent so they are reusable. Also I couldn't make them implement some ValidationRule -> apply(T genericInterface) interface since each ValidationRule may get different parameters. And I don't want to make it more complex by getting parameters from interface, but also open for any suggestions.

@Component
public class AssignedSelectionUniqueRule {

    private AssignedSelectionRepository assignedSelectionRepository;

    public AssignedSelectionUniqueRule(AssignedSelectionRepository assignedSelectionRepository) {
        this.assignedSelectionRepository = assignedSelectionRepository;
    }

    public void apply(AssignSelectionRequestDto objectToValidate) {

        Optional<AssignedSelection> foundAssignedSelection =
            assignedSelectionRepository.getBy(objectToValidate.getSelectionDto().getId(),
                objectToValidate.getCampaignUuid());

        if (foundAssignedSelection.isPresent()) {
            throw new BadRequestException(
                "AssignedSelection is already exists with campaignUuid: {} and selectionUuid: {}");
        }
    }
}

First of all, inside AssignedSelectionValidatorFactory , you should define a HAS-A relationship on Validator , not on its concrete implementation.

     public class AssignedSelectionValidatorFactory implements ValidatorFactory {
         private Validator<T> validator;
.......

When you create your factory object, you will need to pass a valid type for T, which in your case would be AssignedSelectionValidatable

I hope this will solve your problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM