0

I have been playing with the validation pattern from this blog post. Everything works out as expected but I am unable to add generics. Namely,

public interface Validator extends Function<User, ValidationResult> {
    static Validator validate(Predicate<User> tester, String error) {
        return user -> 
            tester.test(user) ? ValidationResult.valid() : 
                    ValidationResult.invalid(error);
    }
}

However, when I try to make the Validator interface generic

public interface Validator<T> extends Function<T, ValidationResult> {
    static Validator validate(Predicate<T> tester, String error) {
        return subject ->
                tester.test(subject) ? ValidationResult.valid() :
                        ValidationResult.invalid(error);
    }
}

I get a compilation error:

Validatior.this cannot be referenced from the static context.

enter image description here

I can't understand why. What am I doing wrong?

AstroSharp
  • 1,872
  • 2
  • 22
  • 31
  • 1
    Does [this](https://stackoverflow.com/questions/936377/static-method-in-a-generic-class) answer your question? – Sweeper Aug 01 '20 at 07:49
  • What exactly is your use case? It's not clear from your code. For example, your _`Validator.validate()`_ returns a _`Validator`_. So what do you intend for callers of that method to do with that _`Validator`_ they get back? Just looking at the code as it is now, the only thing they *can* do is call _`Validator.validate()`_...to get another _`Validator`_???? – deduper Aug 01 '20 at 09:55

2 Answers2

1

„…I can't understand why. What am I doing wrong?…“

What you're doing wrong is referring to the type parameter in a static context. The JLS says that's not allowed

It is a compile-time error to refer to a type parameter of a generic class C in any of the following:

  • the declaration of a static member of C (§8.3.1.1, §8.4.3.2, §8.5.1).

  • the declaration of a static member of any type declaration nested within C.

  • a static initializer of C (§8.7), or

  • a static initializer of any class declaration nested within C.

One way to make your code compile is to change it to this…

public interface Validator<T> extends Function<T, ValidationResult> {
    
    default Validator validate(Predicate<T> tester, String error) {
        return user -> 
            tester.test((T)user) ? ValidationResult.valid() : 
                    ValidationResult.invalid(error);
    }
}
deduper
  • 1,944
  • 9
  • 22
0

My first answer assumes you want nothing more than for the original code you posted to compile; with the fewest changes made to it. So that answer addresses only that assumption.

This is a different answer because it makes a different assumption; and requires more than one code change.

Assumption: You absolutely must have a static method?

You could get that with the following refactors:

  • Introduce a Validatible interface…

      public interface Validatible{ 
    
          boolean isValid();
    
      }
    
  • Make User a Validatiable

      public class User implements Validatible{
          ...
    
          @Override
          public boolean isValid(){
              ...
          }
          ... 
      }
    
  • Simplify Validator

      public interface Validator {
    
          ValidationResult validate(Validatible input);
      }
    
  • Move your must-have static method to a utility/helper class…

      public class DeduperAnswer {
    
          static Validator validate(Predicate<Validatible> tester, String error) {
              return user -> 
                  tester.test(user) ? ValidationResult.valid() : 
                          ValidationResult.invalid(error);
          }
          ...
      }
    

You could then call DeduperAnswer.validate() like I do in this demo

    Validator butWhatThen = DeduperAnswer.validate((user) -> { return user.isValid(); }, "not valid");

But like I asked in the comments, after you get back that Validator from the static method call, what do you intend to do with it then?

I've made the assumptions I've made because it's not 100% clear what your exact use case is. It would be super helpful if you would share that.

deduper
  • 1,944
  • 9
  • 22
  • It's tricky to explain but here is what I am doing: I tried to code the example of User validator from this article: https://gtrefs.github.io/code/combinator-pattern/ It worked as expected. In my project I need to validate many types of objects: `User`, `Product`, `OrderForm`, etc. .. so I wanted to add generic instead of `User` so I can reuse this construct validating other objects. So I needed to change `User` to `` – AstroSharp Aug 02 '20 at 04:06
  • „*...In my project I need to validate many types of objects...so I can reuse this construct validating other objects...*“ — It is true, @AstroSharp, that generics is one way to get polymorphism. But it's not the only way. It's certainly not the simplest way. Some people even [*think that it's the worst way*](https://old.reddit.com/r/java/comments/i08y90/shops_on_java_18_that_use_it_like_java_16/fzre22j/). The _`Validatible`_ interface in this answer provides the subtype polymorphism you're describing. I'm curious to learn what your thoughts are on that approach? – deduper Aug 03 '20 at 02:09