Prüfung von annotierten Funktionsparamatern

Schuriko

Bekanntes Mitglied
Wie kann ich am besten einen unabhängiges Datenfeld einer Validierung unterziehen?

Konkreter Fall:
Ich habe eine Klasse Contact s. https://www.java-forum.org/thema/protected-nicht-protected.185053/

In der Klasse Contact befindet sich ein Attribut "content", welches unterschiedlich Werte (Email, Telephon, Internet, ....) aufnehmen kann.
Die Klasse ist abstrakt, weil es davon abgeleitete für jede Prüfung geben wird. z.B.

Code:
public class EmailContact extends Contact {
   
        public EmailContact(@Email @NotBlank @NotNull String email) {
            super();
           
            this.setMethod(EContactMethod.EMAIL);
            this.setContent(email);
        }
       
        public void setContent(@Email @NotBlank @NotNull String email) {
            super.setContent(email);
        }
}
für Email dürfte das Feld content nicht blank, nicht null sein und es muss eine gültige Email - Adresse haben. Deshalb schreibe ich in den Parametern die Annotations hinzu.

Wie überprüfe ich jetzt aber ob diese auch greifen? Wie müsste eine entsprechende Test-Funktion aussehen?
Meine aktuelle Test-Klasse sieht momentan wie folgt aus (bitte nicht wundern über den assertTrue(true)):
Code:
public class EmailContactTest {

        private Validator validator;
       
        @Before
        public void setUp() throws Exception {
            ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
            validator = factory.getValidator();
        }
       
        /**
         * test initialze constructor with null
         */
        @Test
        public void testEmailContactConstructorWithNull() {
            EmailContact contact = new EmailContact(null);
            assertTrue(true);
        }

}
 

httpdigest

Top Contributor
Im Endeffekt passiert die Validierung nicht "automagisch", sondern in Frameworks wie Spring oder einem Java EE Container, in denen du "Beans" definieren würdest (also Instanzen von Klassen, die durch solche Frameworks instanziiert und gemanaged werden), würden solche Frameworks Proxies um diese Beans legen, so dass jeder Lookup auf ein solches Bean immer den Proxy bekommen würde und Aufrufe immer zuerst gegen den Proxy gehen. Dieser Proxy führt dann die Validierung durch und leitet den eigentlichen Aufruf auf die Zielinstanz.
 

Schuriko

Bekanntes Mitglied
Ich habe mal versucht das besagte für meine Email-Kontakt-Klasse:
Code:
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

public class EmailContact extends AbstractContact {

        public EmailContact() {
            super();

            this.setMethod(EContactMethod.EMAIL);
        }
        
        public EmailContact(EmailContact emailContact) {
            super(emailContact);
        }

        public EmailContact(@Email @NotBlank @NotNull String email) {
            super();
            
            this.setMethod(EContactMethod.EMAIL);
            this.setContent(email);
        }

        public String getContent() {
            return super.getContent();
        }
        
        public void setContent(@Email @NotBlank @NotNull String email) {
            super.setContent(email);
        }
}

über meine Test Klasse
Code:
import static org.junit.Assert.*;

import java.lang.reflect.Method;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.executable.ExecutableValidator;

import org.junit.Before;
import org.junit.Test;

public class EmailContactTest {

        private ExecutableValidator executableValidator;
        
        @Before
        public void setUp() throws Exception {
            ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
            this.executableValidator = factory.getValidator()
                .forExecutables();
        }
        
        @Test
        public void testSetContent() throws NoSuchMethodException {
            EmailContact emailContact = new EmailContact();
            Method method = EmailContact.class.getMethod("setContent", String.class);
            Object[] parameterValues = { null };
            
            Set<ConstraintViolation<EmailContact>> violations
              = executableValidator.validateParameters(emailContact, method, parameterValues);
            
             assertEquals(1, violations.size());
        }
        
}

zu testen. Hierbei erhalte ich allerdings die Meldung:
javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method EmailContact#setContent(String) redefines the configuration of AbstractContact#setContent(String).
at org.hibernate.validator.internal.metadata.aggregated.rule.OverridingMethodMustNotAlterParameterConstraints.apply(OverridingMethodMustNotAlterParameterConstraints.java:24)
at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.assertCorrectnessOfConfiguration(ExecutableMetaData.java:461)
at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.build(ExecutableMetaData.java:377)
at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl$BuilderDelegate.build(BeanMetaDataImpl.java:788)
at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl$BeanMetaDataBuilder.build(BeanMetaDataImpl.java:648)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.createBeanMetaData(BeanMetaDataManager.java:204)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.getBeanMetaData(BeanMetaDataManager.java:166)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:265)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:233)
at com.abado.project.entities.EmailContactTest.testSetContent(EmailContactTest.java:41)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

und weis nicht wo der Fehler liegt.
 

thecain

Top Contributor
Du darfst auf der erbenden Klasse nicht andere Validierungen als auf der Parent klasse haben. Wie in der Fehlermeldung auch steht:

: A method overriding another method must not redefine the parameter constraint configuration, but method EmailContact#setContent(String) redefines the configuration of AbstractContact#setContent(String).
 

Schuriko

Bekanntes Mitglied
Hmm, ok! Wie würdet ihr das Problem lösen? Sprich eine Abstrakte Klasse dient als Basis und die Werte dürfen nur entsprechend Ihrer Validation in einem String - Feld abgelegt werden.
 

mrBrown

Super-Moderator
Mitarbeiter
Entweder keine abstrakte Klasse, sondern eigenen Validator für die Kombination Typ+Content.

Oder keine abstrakte Klasse, dafür eine eigene Klasse für den Content (also statt String content irgendwas in die Richtung von ContectInformation content und class EmailAdress implements ContectInformation)

Oder abstrakte Klasse, aber mit abstraktem Getter/Setter und das Feld erst in der Subklasse mit Annotations definieren.
 

Ähnliche Java Themen

Neue Themen


Oben