title: Java records validation fail when using byte buddy
body: <p>So i'm trying to do validation of java records as its done <a href="https://www.morling.dev/blog/enforcing-java-record-invariants-with-bean-validation/" rel="nofollow noreferrer"> in this article</a></p>
  <p>I have a custom validator for validating phone number that uses google's phone number library and i'm getting the following error when I try to build and when I run the validation tests the validation is ignored and it fails.</p>
  <pre><code>Failed to execute goal net.bytebuddy:byte-buddy-maven-plugin:1.12.9:transform (default) on project deposits: 
  Failed to transform class files in deposits-api/target/classes: 
  None of public static void com.validations.RecordValidationInterceptor.validate(java.lang.reflect.Constructor,java.lang.Object[])
  allows for delegation from 
  public com.models.OnlinePaymentRequest(java.lang.String,java.math.BigDecimal,java.lang.String,java.lang.String,java.lang.String,int)
  </code></pre>
  <p>model</p>
  <pre><code>public record OnlinePaymentRequest(
      @JsonProperty(&quot;transactionId&quot;)
      @NotBlank(message = &quot;transactionId Value cannot be null or blank&quot;)
      String transactionId,
      
      @JsonProperty(&quot;amount&quot;)
      @DecimalMax(&quot;70000.00&quot;)
      BigDecimal amount,
      
      @JsonProperty(&quot;msisdn&quot;)
      @KEPhoneNumber
      String msisdn,
      
      @JsonProperty(&quot;paybill&quot;)
      @NotBlank(message = &quot;paybill Value cannot be null or blank&quot;)
      String paybill,
      
      @JsonProperty(&quot;accountReference&quot;)
      @NotNull(message = &quot;accountReference Value cannot be null&quot;)
      String accountReference,
      
      @JsonProperty(&quot;userId&quot;)
      @Positive(message = &quot;userId Value cannot be a negative number&quot;)
      int userId) {
    
  }
  </code></pre>
  <p>validator plugin and interceptor classes</p>
  <pre><code>public class RecordValidationPlugin implements Plugin{
  
      @Override
      public boolean matches(TypeDescription target) {
          return target.getDeclaredMethods()
                  .stream()
                  .anyMatch(m -&gt; m.isConstructor() &amp;&amp; isConstrained(m));
      }
  
      @Override
      public Builder&lt;?&gt; apply(Builder&lt;?&gt; builder, TypeDescription typeDescription, ClassFileLocator classFileLocator) {
          return builder.constructor(this::isConstrained)
                  .intercept(SuperMethodCall.INSTANCE.andThen(
                          MethodDelegation.to(RecordValidationInterceptor.class)));
      }
  
      private boolean isConstrained(MethodDescription method) {
          return hasConstrainedReturnValue(method) || hasConstrainedParameter(method);
      }
  
      private boolean hasConstrainedReturnValue(MethodDescription method) {
          return !method.getDeclaredAnnotations()
                  .asTypeList()
                  .filter(hasAnnotation(annotationType(Constraint.class)))
                  .isEmpty();
      }
  
      private boolean hasConstrainedParameter(MethodDescription method) {
          return method.getParameters()
                  .asDefined()
                  .stream()
                  .anyMatch(p -&gt; isConstrained(p));
      }
  
      private boolean isConstrained(ParameterDescription.InDefinedShape parameter) {
          return !parameter.getDeclaredAnnotations()
                  .asTypeList()
                  .filter(hasAnnotation(annotationType(Constraint.class)))
                  .isEmpty();
      }
  
      @Override
      public void close() throws IOException {
      }
  }
  
  public class RecordValidationInterceptor {
  
      private static final Validator VALIDATOR;
  
      static {
          ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
          VALIDATOR = factory.getValidator();
      }
  
      public static &lt;T&gt; void validate(@Origin Constructor&lt;T&gt; constructor, @AllArguments Object[] args) {
          Set&lt;ConstraintViolation&lt;T&gt;&gt; violations = VALIDATOR.forExecutables()
                  .validateConstructorParameters(constructor, args);
          if (!violations.isEmpty()) {
              String message = violations.stream()
                      .map(ConstraintViolation::getMessage)
                      .collect(Collectors.joining(System.lineSeparator()));
              throw new ConstraintViolationException(message, violations);
          }
      }
  
  }
  </code></pre>
  <p>custom validator</p>
  <pre><code>@Target( { ElementType.METHOD, ElementType.FIELD })
  @Retention(RetentionPolicy.RUNTIME)
  @Documented
  @Constraint(validatedBy = KEPhoneNumberValidator.class)
  public @interface KEPhoneNumber {
      public String message() default &quot;Invalid phone number.&quot;;
      public Class&lt;?&gt;[] groups() default {};
       public Class&lt;? extends Payload&gt;[] payload() default {};
  }
  public class KEPhoneNumberValidator implements ConstraintValidator&lt;KEPhoneNumber, String&gt; {
  
      @Override
      public void initialize(KEPhoneNumber constraintAnnotation) {
          
      }
  
      @Override
      public boolean isValid(String value, ConstraintValidatorContext context) {
          LOGGER.info(&quot;validating phone number: &quot;+value+&quot; ........&quot;);
          return isMsisdnValid(value);
      }
      
      public static boolean isMsisdnValid(String msisdn) {
          PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
          boolean isValid = false;
          try {
              Phonenumber.PhoneNumber kenyaNumberProto = phoneUtil.parse(msisdn, &quot;KE&quot;);
              isValid = phoneUtil.isValidNumber(kenyaNumberProto);
          } catch (NumberParseException e) {
              LOGGER.info(&quot;NumberParseException was thrown: &quot; + e.toString());
          }
          return isValid;
      }
      
  }
  </code></pre>
  <p>the test</p>
  <pre><code>@Test
      public void canValidateOnlinePaymentReQuest() throws Exception {
          OnlinePaymentRequest valid = new OnlinePaymentRequest(&quot;WIWU87v3XXHT&quot;, BigDecimal.ONE, &quot;254725909090&quot;, &quot;3009809&quot;, &quot;USER-001&quot;, 4);
          System.out.println(valid);
  
          try {
              OnlinePaymentRequest invalid = new OnlinePaymentRequest(null, BigDecimal.ONE, &quot;&quot;, &quot;3009809&quot;, &quot;USER-001&quot;, -10);
              System.out.println(invalid);
              fail(&quot;Expected ConstraintViolationException not thrown&quot;);
          }
          catch(ConstraintViolationException cve) {
              System.out.println(cve.getMessage());
              assertEquals(3, cve.getConstraintViolations().size());
          }
      }
  </code></pre>