wink-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gpetra...@apache.org
Subject svn commit: r1511849 [1/2] - in /wink/2.x/trunk: ./ wink-bv-server/ wink-bv-server/src/ wink-bv-server/src/main/ wink-bv-server/src/main/java/ wink-bv-server/src/main/java/org/ wink-bv-server/src/main/java/org/apache/ wink-bv-server/src/main/java/org/a...
Date Thu, 08 Aug 2013 16:17:06 GMT
Author: gpetracek
Date: Thu Aug  8 16:17:04 2013
New Revision: 1511849

URL: http://svn.apache.org/r1511849
Log:
WINK-401 integration of bean-validation 1.1 (first draft)

Added:
    wink/2.x/trunk/wink-bv-server/
    wink/2.x/trunk/wink-bv-server/pom.xml
    wink/2.x/trunk/wink-bv-server/src/
    wink/2.x/trunk/wink-bv-server/src/main/
    wink/2.x/trunk/wink-bv-server/src/main/java/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationExceptionMapper.java
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationInvocationValidator.java
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/InvocationTargetViolationException.java
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/MethodMetaDataCache.java
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/ValidationModeEvaluator.java
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/util/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/util/ReflectionUtils.java
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/spi/
    wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/spi/ConstraintViolationEntityFactory.java
    wink/2.x/trunk/wink-bv-server/src/main/resources/
    wink/2.x/trunk/wink-bv-server/src/main/resources/META-INF/
    wink/2.x/trunk/wink-bv-server/src/main/resources/META-INF/services/
    wink/2.x/trunk/wink-bv-server/src/main/resources/META-INF/services/org.apache.wink.server.internal.validation.InvocationValidator
    wink/2.x/trunk/wink-bv-server/src/test/
    wink/2.x/trunk/wink-bv-server/src/test/java/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/BeanValidationIntegrationTest.java
    wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/ValidateOnExecutionTest.java
    wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/BootstrappingContext.java
    wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/validation/
    wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/validation/InvocationValidator.java
Modified:
    wink/2.x/trunk/pom.xml
    wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java
    wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/InvokeMethodHandler.java
    wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java
    wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/servlet/RestServlet.java

Modified: wink/2.x/trunk/pom.xml
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/pom.xml?rev=1511849&r1=1511848&r2=1511849&view=diff
==============================================================================
--- wink/2.x/trunk/pom.xml (original)
+++ wink/2.x/trunk/pom.xml Thu Aug  8 16:17:04 2013
@@ -58,6 +58,7 @@
         <module>wink-guice-server</module>
         <module>wink-examples</module>
         <module>wink-assembly</module>
+        <module>wink-bv-server</module>
         <module>wink-osgi</module>
     </modules>
     <scm>

Added: wink/2.x/trunk/wink-bv-server/pom.xml
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/pom.xml?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/pom.xml (added)
+++ wink/2.x/trunk/wink-bv-server/pom.xml Thu Aug  8 16:17:04 2013
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+    
+     http://www.apache.org/licenses/LICENSE-2.0
+    
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>wink</artifactId>
+        <groupId>org.apache.wink</groupId>
+        <version>1.4.0-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.wink</groupId>
+    <artifactId>wink-bv-server</artifactId>
+    <name>Apache Wink :: BeanValidation Integration</name>
+    <dependencies>
+        <!-- needed until we have an api-version of geronimo-specs for bv 1.1 -->
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-validator</artifactId>
+            <version>5.0.1.Final</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.wink</groupId>
+            <artifactId>wink-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_3.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+             <groupId>org.apache.wink</groupId>
+             <artifactId>wink-component-test-support</artifactId>
+         </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jmock</groupId>
+            <artifactId>jmock-junit3</artifactId>
+            <version>2.5.1</version>
+            <scope>test</scope>
+        </dependency>
+       <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-jdk14</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

Added: wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationExceptionMapper.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationExceptionMapper.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationExceptionMapper.java (added)
+++ wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationExceptionMapper.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.wink.bv.server.internal.validation.bv;
+
+import org.apache.wink.bv.server.spi.ConstraintViolationEntityFactory;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ValidationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+@Provider
+public class BeanValidationExceptionMapper implements ExceptionMapper<ValidationException> {
+
+    @Override
+    public Response toResponse(ValidationException e) {
+        MediaType targetMediaType = MediaType.TEXT_PLAIN_TYPE;
+        Response.Status targetStatus = Response.Status.INTERNAL_SERVER_ERROR;
+        Object entity = e.getMessage();
+
+        if (e instanceof InvocationTargetViolationException) {
+            InvocationTargetViolationException constraintViolationException = (InvocationTargetViolationException)e;
+
+            EntityResult result = createViolationEntityResult(constraintViolationException);
+            targetMediaType = result.mediaType;
+            entity = result.entity;
+
+            //violation in result -> INTERNAL_SERVER_ERROR (before it is BAD_REQUEST)
+            //alternative: check for javax.validation.ElementKind.RETURN_VALUE
+            targetStatus = constraintViolationException.getTargetStatusCode();
+        }
+        return Response.status(targetStatus).type(targetMediaType).entity(entity).build();
+    }
+
+    private EntityResult createViolationEntityResult(InvocationTargetViolationException e) {
+        EntityResult entityResult = new EntityResult();
+        ConstraintViolationEntityFactory entityFactory =
+                getConstraintViolationEntityFactory(e.getAcceptableMediaTypes(), entityResult);
+
+        entityResult.entity = entityFactory.createEntity(e.getConstraintViolations());
+        return entityResult;
+    }
+
+    private ConstraintViolationEntityFactory getConstraintViolationEntityFactory(
+            List<MediaType> acceptableMediaTypes, EntityResult entityResult) {
+
+        ServiceLoader<ConstraintViolationEntityFactory> entityFactories =
+                ServiceLoader.load(ConstraintViolationEntityFactory.class); //TODO discuss and add cache
+
+        for (MediaType mediaType : acceptableMediaTypes) {
+            for (ConstraintViolationEntityFactory entityFactory : entityFactories) {
+                if (entityFactory.isResponsibleFor(mediaType)) {
+                    entityResult.mediaType = mediaType;
+                    return entityFactory;
+                }
+            }
+        }
+        return new ConstraintViolationEntityFactory() {
+            @Override
+            public boolean isResponsibleFor(MediaType mediaType) {
+                throw new UnsupportedOperationException("calling the method externally isn't supported");
+            }
+
+            @Override
+            public Object createEntity(Set<ConstraintViolation<?>> constraintViolations) {
+                List<String> violationMessages = new ArrayList<String>();
+                for (ConstraintViolation constraintViolation : constraintViolations) {
+                    //TODO discuss: check/extract jax-rs annotations from the property-path to provide external names
+                    //otherwise it shows e.g. resMethod.arg0, names of the instance-variables of resource-classes,...
+                    violationMessages.add("'" +
+                            constraintViolation.getPropertyPath().toString() + "' " + constraintViolation.getMessage());
+                }
+                //a deterministic result is easier for testing,...
+                Collections.sort(violationMessages);
+
+                StringBuilder result = new StringBuilder();
+
+                for (String violation : violationMessages) {
+                    if (result.length() != 0) {
+                        result.append("; ");
+                    }
+                    result.append(violation);
+                }
+
+                return result.toString();
+            }
+        };
+    }
+
+    private class EntityResult {
+        private Object entity;
+        private MediaType mediaType = MediaType.TEXT_PLAIN_TYPE;
+    }
+}

Added: wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationInvocationValidator.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationInvocationValidator.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationInvocationValidator.java (added)
+++ wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/BeanValidationInvocationValidator.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,279 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.wink.bv.server.internal.validation.bv;
+
+import org.apache.wink.common.RuntimeContext;
+import org.apache.wink.common.WinkApplication;
+import org.apache.wink.common.internal.lifecycle.LifecycleManagersRegistry;
+import org.apache.wink.common.internal.lifecycle.ObjectFactory;
+import org.apache.wink.common.internal.registry.ProvidersRegistry;
+import org.apache.wink.server.handlers.MessageContext;
+import org.apache.wink.server.internal.BootstrappingContext;
+import org.apache.wink.server.internal.validation.InvocationValidator;
+
+import javax.validation.Configuration;
+import javax.validation.ConstraintViolation;
+import javax.validation.ElementKind;
+import javax.validation.MessageInterpolator;
+import javax.validation.Path;
+import javax.validation.TraversableResolver;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorContext;
+import javax.validation.ValidatorFactory;
+import javax.validation.metadata.BeanDescriptor;
+import javax.validation.metadata.MethodDescriptor;
+import javax.ws.rs.core.Response;
+import java.beans.Introspector;
+import java.lang.annotation.ElementType;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+public class BeanValidationInvocationValidator implements InvocationValidator {
+    private ValidatorFactory validatorFactory;
+
+    private boolean executableValidationEnabled;
+
+    private MethodMetaDataCache methodMetaDataCache;
+
+    @Override
+    public boolean init(RuntimeContext context,
+                        LifecycleManagersRegistry lifecycleManagersRegistry,
+                        ProvidersRegistry providersRegistry) {
+
+        Configuration configuration = resolveOrCreateBeanValidationConfiguration(lifecycleManagersRegistry);
+
+        methodMetaDataCache = MethodMetaDataCache.create(
+                configuration.getBootstrapConfiguration().getDefaultValidatedExecutableTypes());
+        executableValidationEnabled = configuration.getBootstrapConfiguration().isExecutableValidationEnabled();
+        validatorFactory = resolveOrCreateValidatorFactory(lifecycleManagersRegistry, configuration);
+
+        providersRegistry.addProvider(BeanValidationExceptionMapper.class, WinkApplication.SYSTEM_PRIORITY, true);
+
+        return true;
+    }
+
+    private static ValidatorFactory resolveOrCreateValidatorFactory(LifecycleManagersRegistry lifecycleManagersRegistry,
+                                                                    Configuration configuration) {
+        try {
+            ObjectFactory<ValidatorFactory> validatorObjectFactory =
+                    lifecycleManagersRegistry.getObjectFactory(ValidatorFactory.class);
+
+            //will find e.g. factory exposed by cdi (which provides other integrations)
+            return validatorObjectFactory.getInstance(new BootstrappingContext());
+        } catch (RuntimeException e) {
+            return configuration.buildValidatorFactory();
+        }
+    }
+
+    private static Configuration resolveOrCreateBeanValidationConfiguration(
+            LifecycleManagersRegistry lifecycleManagersRegistry) {
+        try {
+            ObjectFactory<Configuration> configurationValidatorObjectFactory =
+                    lifecycleManagersRegistry.getObjectFactory(Configuration.class);
+
+            return configurationValidatorObjectFactory.getInstance(new BootstrappingContext());
+        } catch (RuntimeException e) {
+            return Validation.byDefaultProvider().configure();
+        }
+    }
+
+    @Override
+    public ValidationTask createValidationTaskFor(MessageContext context /*not needed for bv right now*/,
+                                                  Object invocationTargetInstance,
+                                                  Method invocationTargetMethod,
+                                                  Object... arguments) {
+        return new BeanValidationTask(invocationTargetInstance, invocationTargetMethod, context, arguments);
+    }
+
+    @Override
+    public void reset() {
+        //TODO discuss this.validatorFactory = null;
+        this.methodMetaDataCache.reset();
+    }
+
+    private class BeanValidationTask implements ValidationTask {
+        private final Object invocationTargetInstance;
+        private final Method invocationTargetMethod;
+        private final Object[] arguments;
+
+        private final Validator validator;
+        private final BeanDescriptor beanDescriptor;
+        private final MethodDescriptor methodDescriptor;
+        private final MessageContext messageContext;
+        private final Locale currentLocale;
+        private final ValidationProcessAwareTraversableResolver traversableResolver;
+
+        public BeanValidationTask(Object invocationTargetInstance,
+                                  Method invocationTargetMethod,
+                                  MessageContext context,
+                                  Object... arguments) {
+            if (invocationTargetInstance == null) {
+                throw new IllegalArgumentException("instance to validate is null");
+            }
+
+            this.invocationTargetInstance = invocationTargetInstance;
+            this.invocationTargetMethod = invocationTargetMethod;
+
+            this.messageContext = context;
+            this.currentLocale = context.getHttpHeaders().getLanguage();
+
+            this.arguments = arguments;
+
+            MethodMetaDataCache.ValidationMethodDescriptor validationMethodDescriptor=
+                    methodMetaDataCache.get(invocationTargetMethod);
+
+            ValidatorContext validatorContext = validatorFactory.usingContext();
+            traversableResolver = new ValidationProcessAwareTraversableResolver(
+                    validatorFactory.getTraversableResolver(), invocationTargetMethod, validationMethodDescriptor);
+            validatorContext.traversableResolver(traversableResolver);
+            if (currentLocale != null) {
+                validatorContext.messageInterpolator(new LocaleAwareMessageInterpolator(
+                        validatorFactory.getMessageInterpolator(), currentLocale));
+            }
+            this.validator = validatorContext.getValidator();
+
+            Class<?> targetClass = invocationTargetInstance.getClass();
+            this.beanDescriptor = validator.getConstraintsForClass(targetClass);
+
+            if (executableValidationEnabled && validationMethodDescriptor.isValidationAllowed()) {
+                this.methodDescriptor = beanDescriptor.getConstraintsForMethod(
+                        invocationTargetMethod.getName(), invocationTargetMethod.getParameterTypes());
+            } else {
+                this.methodDescriptor = null;
+            }
+        }
+
+        @Override
+        public ValidationTask validateBeforeTargetInvocation() {
+            Set<ConstraintViolation<Object>> constraintViolations = new HashSet<ConstraintViolation<Object>>();
+            if (beanDescriptor.isBeanConstrained()) {
+                traversableResolver.jaxRsResourceObjectValidation = true;
+                constraintViolations.addAll(validator.validate(invocationTargetInstance));
+                traversableResolver.jaxRsResourceObjectValidation = false;
+            }
+
+            if (methodDescriptor != null && methodDescriptor.hasConstrainedParameters()) {
+                constraintViolations.addAll(validator.forExecutables()
+                        .validateParameters(invocationTargetInstance, invocationTargetMethod, arguments));
+            }
+
+            if (!constraintViolations.isEmpty()) {
+                throw new InvocationTargetViolationException(constraintViolations,
+                        Response.Status.BAD_REQUEST,
+                        messageContext.getHttpHeaders().getAcceptableMediaTypes());
+            }
+            return this;
+        }
+
+        @Override
+        public ValidationTask validateInvocationResult(Object result) {
+            if (methodDescriptor == null || !methodDescriptor.hasConstrainedReturnValue()) {
+                return this;
+            }
+
+            Set<ConstraintViolation<Object>> constraintViolations = validator.forExecutables()
+                    .validateReturnValue(invocationTargetInstance, invocationTargetMethod, result);
+
+            if (!constraintViolations.isEmpty()) {
+                throw new InvocationTargetViolationException(constraintViolations,
+                        Response.Status.INTERNAL_SERVER_ERROR,
+                        messageContext.getHttpHeaders().getAcceptableMediaTypes());
+            }
+            return this;
+        }
+    }
+
+    private class LocaleAwareMessageInterpolator implements MessageInterpolator {
+        private MessageInterpolator wrapped;
+        private Locale currentLocale;
+
+        public LocaleAwareMessageInterpolator(MessageInterpolator wrapped, Locale currentLocale) {
+            this.wrapped = wrapped;
+            this.currentLocale = currentLocale;
+        }
+
+        @Override
+        public String interpolate(String messageTemplate, Context context) {
+            return interpolate(messageTemplate, context, null);
+        }
+
+        @Override
+        public String interpolate(String messageTemplate, Context context, Locale locale) {
+            return wrapped.interpolate(messageTemplate, context, this.currentLocale);
+        }
+    }
+
+    //to avoid that javax.validation.Validator#validate does invoke the >invocationTargetMethod< if it's also a getter
+    private class ValidationProcessAwareTraversableResolver implements TraversableResolver {
+
+        private final TraversableResolver wrapped;
+        private final Class invocationTargetClass;
+        private final String propertyName;
+        private boolean jaxRsResourceObjectValidation;
+
+        private ValidationProcessAwareTraversableResolver(TraversableResolver wrapped,
+                                                          Method invocationTargetMethod,
+                                                          MethodMetaDataCache.ValidationMethodDescriptor descriptor) {
+            this.wrapped = wrapped;
+            this.invocationTargetClass = invocationTargetMethod.getDeclaringClass();
+
+            if (descriptor.isGetterMethod()) {
+                if (invocationTargetMethod.getName().startsWith("is")) {
+                    propertyName = Introspector.decapitalize(invocationTargetMethod.getName().substring(2));
+                } else {
+                    propertyName = Introspector.decapitalize(invocationTargetMethod.getName().substring(3));
+                }
+            } else {
+                this.propertyName = null;
+            }
+        }
+
+        @Override
+        public boolean isReachable(Object traversableObject,
+                                   Path.Node traversableProperty,
+                                   Class<?> rootBeanType,
+                                   Path pathToTraversableObject,
+                                   ElementType elementType) {
+            //noinspection SimplifiableIfStatement
+            if (jaxRsResourceObjectValidation && propertyName != null && traversableObject != null &&
+                    invocationTargetClass.equals(traversableObject.getClass()) &&
+                    ElementType.METHOD.equals(elementType) &&
+                    ElementKind.PROPERTY.equals(traversableProperty.getKind()) &&
+                    propertyName.equals(traversableProperty.getName()) /*ok since bv just pass in getter-methods*/) {
+                return false;
+            }
+            return wrapped.isReachable(
+                    traversableObject, traversableProperty, rootBeanType, pathToTraversableObject, elementType);
+        }
+
+        @Override
+        public boolean isCascadable(Object traversableObject,
+                                    Path.Node traversableProperty,
+                                    Class<?> rootBeanType,
+                                    Path pathToTraversableObject,
+                                    ElementType elementType) {
+            return wrapped.isCascadable(
+                    traversableObject, traversableProperty, rootBeanType, pathToTraversableObject, elementType);
+        }
+    }
+}

Added: wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/InvocationTargetViolationException.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/InvocationTargetViolationException.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/InvocationTargetViolationException.java (added)
+++ wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/InvocationTargetViolationException.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.wink.bv.server.internal.validation.bv;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+import java.util.Set;
+
+class InvocationTargetViolationException extends ConstraintViolationException {
+    private static final long serialVersionUID = -6228734442141897137L;
+    private final Response.Status targetStatusCode;
+    private final List<MediaType> acceptableMediaTypes;
+
+    InvocationTargetViolationException(Set<ConstraintViolation<Object>> constraintViolations,
+                                       Response.Status targetStatusCode,
+                                       List<MediaType> acceptableMediaTypes) {
+        super(constraintViolations);
+        this.targetStatusCode = targetStatusCode;
+        this.acceptableMediaTypes = acceptableMediaTypes;
+    }
+
+    Response.Status getTargetStatusCode() {
+        return targetStatusCode;
+    }
+
+    List<MediaType> getAcceptableMediaTypes() {
+        return acceptableMediaTypes;
+    }
+}

Added: wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/MethodMetaDataCache.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/MethodMetaDataCache.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/MethodMetaDataCache.java (added)
+++ wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/MethodMetaDataCache.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.wink.bv.server.internal.validation.bv;
+
+import javax.validation.executable.ExecutableType;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+class MethodMetaDataCache {
+    private final ValidationModeEvaluator.ValidationModeDescriptor defaultValidationModeDescriptor;
+
+    private Map<Method, ValidationMethodDescriptor> methodMetaData =
+            new ConcurrentHashMap<Method, ValidationMethodDescriptor>();
+
+    public static MethodMetaDataCache create(Collection<ExecutableType> defaultExecutableTypes) {
+        return new MethodMetaDataCache(ValidationModeEvaluator.convertToDescriptor(defaultExecutableTypes));
+    }
+
+    private MethodMetaDataCache(ValidationModeEvaluator.ValidationModeDescriptor validationModeDescriptor) {
+        this.defaultValidationModeDescriptor = validationModeDescriptor;
+    }
+
+    public ValidationMethodDescriptor get(Method targetMethod) {
+        ValidationMethodDescriptor result = methodMetaData.get(targetMethod);
+
+        if (result == null) {
+            result = new ValidationMethodDescriptor(targetMethod);
+            methodMetaData.put(targetMethod, result);
+        }
+        return result;
+    }
+
+    public void reset() {
+        methodMetaData.clear();
+    }
+
+    class ValidationMethodDescriptor {
+        private final boolean isGetterMethod;
+        private final ValidationModeEvaluator.ValidationModeDescriptor modeForMethod;
+
+        ValidationMethodDescriptor(Method targetMethod) {
+            this.modeForMethod = ValidationModeEvaluator.ValidationModeDescriptor
+                    .createFor(targetMethod, defaultValidationModeDescriptor);
+
+            Class returnType = targetMethod.getReturnType();
+            isGetterMethod = targetMethod.getParameterTypes().length == 0 &&
+                    ((void.class != returnType && targetMethod.getName().startsWith("get")) ||
+                            (boolean.class == returnType && targetMethod.getName().startsWith("is")));
+        }
+
+        boolean isValidationAllowed() {
+            if (isGetterMethod) {
+                return modeForMethod.isValidateGetterMethodsAllowed();
+            }
+            return modeForMethod.isImplicitMode() || modeForMethod.isValidateNonGetterMethodsAllowed();
+        }
+
+        boolean isGetterMethod() {
+            return isGetterMethod;
+        }
+    }
+}

Added: wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/ValidationModeEvaluator.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/ValidationModeEvaluator.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/ValidationModeEvaluator.java (added)
+++ wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/ValidationModeEvaluator.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.wink.bv.server.internal.validation.bv;
+
+import org.apache.wink.bv.server.internal.validation.bv.util.ReflectionUtils;
+
+import javax.validation.executable.ExecutableType;
+import javax.validation.executable.ValidateOnExecution;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+
+public class ValidationModeEvaluator {
+    public static ValidationModeDescriptor convertToDescriptor(Collection<ExecutableType> executableTypes) {
+        //TODO discuss the defaults (the first and last paragraph of section 7.4 of the jax-rs spec. are contradicting)
+        //introduce wink specific config to switch between the behaviour described in both paragraphs
+        boolean implicitMode = false;
+        //won't lead to an invocation on the resource-instance level (see ValidationProcessAwareTraversableResolver)
+        boolean validateGetterMethods = true;
+        boolean validateNonGetterMethods = false;
+
+        for (ExecutableType executableType : executableTypes) {
+            switch (executableType) {
+                case IMPLICIT:
+                    implicitMode = true;
+                    break;
+                case GETTER_METHODS:
+                    validateGetterMethods = true;
+                    break;
+                case NON_GETTER_METHODS:
+                    validateNonGetterMethods = true;
+                    break;
+                case ALL:
+                    implicitMode = true;
+                    validateGetterMethods = true;
+                    validateNonGetterMethods = true;
+                    break;
+            }
+        }
+        if (executableTypes.isEmpty()) {
+            implicitMode = true;
+        }
+
+        return new ValidationModeDescriptor(implicitMode, validateGetterMethods, validateNonGetterMethods);
+    }
+
+    static class ValidationModeDescriptor implements Serializable {
+        private static final long serialVersionUID = 6135091317703959078L;
+
+        private final boolean implicitMode;
+        private final boolean validateGetterMethods;
+        private final boolean validateNonGetterMethods;
+
+        ValidationModeDescriptor(boolean implicitModeDefaultValue,
+                                 boolean validateGetterMethodsDefaultValue,
+                                 boolean validateNonGetterMethodsDefaultValue) {
+            implicitMode = implicitModeDefaultValue;
+            validateGetterMethods = validateGetterMethodsDefaultValue;
+            validateNonGetterMethods = validateNonGetterMethodsDefaultValue;
+        }
+
+        public static ValidationModeDescriptor createFor(Method targetMethod, ValidationModeDescriptor defaultEntry) {
+            ValidateOnExecution validateOnExecution = ReflectionUtils.extractValidateOnExecutionFrom(targetMethod);
+
+            if (validateOnExecution == null) {
+                return defaultEntry;
+
+            }
+            return convertToDescriptor(Arrays.asList(validateOnExecution.type()));
+        }
+
+        boolean isImplicitMode() {
+            return implicitMode;
+        }
+
+        boolean isValidateGetterMethodsAllowed() {
+            return validateGetterMethods;
+        }
+
+        boolean isValidateNonGetterMethodsAllowed() {
+            return validateNonGetterMethods;
+        }
+    }
+}

Added: wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/util/ReflectionUtils.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/util/ReflectionUtils.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/util/ReflectionUtils.java (added)
+++ wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/internal/validation/bv/util/ReflectionUtils.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.wink.bv.server.internal.validation.bv.util;
+
+import javax.validation.executable.ValidateOnExecution;
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ReflectionUtils {
+    private ReflectionUtils() {
+    }
+
+    public static ValidateOnExecution extractValidateOnExecutionFrom(Method targetMethod) {
+        //find the topmost method in the inheritance hierarchy and check the method and fallback to the same class
+        targetMethod = getTopmostMethod(targetMethod.getDeclaringClass(), targetMethod, targetMethod);
+        ValidateOnExecution result = targetMethod.getAnnotation(ValidateOnExecution.class);
+
+        if (result != null) {
+            return result;
+        }
+        return targetMethod.getDeclaringClass().getAnnotation(ValidateOnExecution.class);
+    }
+
+    private static Method getTopmostMethod(Class<?> declaringClass, Method currentMethod, Method originalMethod) {
+        if (declaringClass == null || Object.class.equals(declaringClass)) {
+            return currentMethod;
+        }
+
+        try {
+            Method overriddenMethod =
+                    declaringClass.getMethod(currentMethod.getName(), currentMethod.getParameterTypes());
+            return getTopmostMethod(declaringClass.getSuperclass(), overriddenMethod, originalMethod);
+        } catch (NoSuchMethodException e) {
+            for (Method method : declaringClass.getMethods()) {
+                if (method.getParameterTypes().length == currentMethod.getParameterTypes().length &&
+                        method.getName().equals(currentMethod.getName()) &&
+                        parameterTypesCompatible(method, originalMethod)) {
+                    return getTopmostMethod(declaringClass.getSuperclass(), method, originalMethod);
+                }
+            }
+            return currentMethod;
+        }
+    }
+
+    private static boolean parameterTypesCompatible(Method currentMethod, Method originalMethod) {
+        Type[] resolvedTypes = resolveParameterTypes(originalMethod.getDeclaringClass(), currentMethod);
+
+        Class<?>[] parameterTypes = originalMethod.getParameterTypes();
+        if (resolvedTypes.length != parameterTypes.length) {
+            return false; //unexpected -> TODO discuss logging vs exception
+        }
+        for (int i = 0; i < parameterTypes.length; i++) {
+            if (!resolvedTypes[i].equals(originalMethod.getParameterTypes()[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * the following part is used in apache openwebbeans to handle generics correctly
+     * TODO replace it with commons-lang3 once it provides a correct implementation
+     */
+
+    public static Type[] resolveParameterTypes(Class<?> subclass, Method method) {
+        return resolveTypes(method.getGenericParameterTypes(), new TypeVariableResolver(subclass, method.getDeclaringClass()));
+    }
+
+    public static Type[] resolveTypes(Type[] types, TypeVariableResolver resolution) {
+        Type[] resolvedTypeArguments = new Type[types.length];
+        for (int i = 0; i < types.length; i++) {
+            resolvedTypeArguments[i] = resolveType(types[i], resolution);
+        }
+        return resolvedTypeArguments;
+    }
+
+    private static Type resolveType(Type type, TypeVariableResolver resolver) {
+        if (type instanceof Class) {
+            return type;
+        } else if (type instanceof ParameterizedType) {
+            ParameterizedType parameterizedType = (ParameterizedType) type;
+            Type[] resolvedTypes = resolveTypes(parameterizedType.getActualTypeArguments(), resolver);
+            return new ParametrizedTypeImpl(parameterizedType.getOwnerType(), parameterizedType.getRawType(), resolvedTypes);
+        } else if (type instanceof TypeVariable) {
+            TypeVariable<?> variable = (TypeVariable<?>) type;
+            return resolver.resolve(variable);
+        } else if (type instanceof WildcardType) {
+            WildcardType wildcardType = (WildcardType) type;
+            if (wildcardType.getLowerBounds().length > 0) {
+                return type;
+            }
+            Type[] resolvedTypes = resolveTypes(wildcardType.getUpperBounds(), resolver);
+            return resolveType(getMostSpecificType(getRawTypes(resolvedTypes, resolver), resolvedTypes), resolver);
+        } else if (type instanceof GenericArrayType) {
+            Type componentType = resolveType(((GenericArrayType) type).getGenericComponentType(), resolver);
+            Class<?> componentClass = getRawType(componentType, resolver);
+            return Array.newInstance(componentClass, 0).getClass();
+        } else {
+            throw new IllegalArgumentException("Unsupported type " + type.getClass().getName());
+        }
+    }
+
+    private static Type getMostSpecificType(Class<?>[] types, Type[] genericTypes) {
+        Class<?> mostSpecificType = types[0];
+        int mostSpecificIndex = 0;
+        for (int i = 0; i < types.length; i++) {
+            if (mostSpecificType.isAssignableFrom(types[i])) {
+                mostSpecificType = types[i];
+                mostSpecificIndex = i;
+            }
+        }
+        return genericTypes[mostSpecificIndex];
+    }
+
+    private static <T> Class<T>[] getRawTypes(Type[] types, TypeVariableResolver resolver) {
+        //noinspection unchecked
+        Class<T>[] rawTypes = new Class[types.length];
+        for (int i = 0; i < types.length; i++) {
+            rawTypes[i] = getRawType(types[i], resolver);
+        }
+        return rawTypes;
+    }
+
+    static <T> Class<T> getRawType(Type type, TypeVariableResolver resolver) {
+        if (type instanceof Class) {
+            //noinspection unchecked
+            return (Class<T>) type;
+        } else if (type instanceof ParameterizedType) {
+            return getRawType(((ParameterizedType) type).getRawType(), resolver);
+        } else if ((type instanceof TypeVariable) || (type instanceof WildcardType) || (type instanceof GenericArrayType)) {
+            Type resolvedType = resolveType(type, resolver);
+            if (resolvedType instanceof TypeVariable) {
+                TypeVariable<?> variable = (TypeVariable<?>) resolvedType;
+                return getRawType(resolveType(getRawType(variable.getBounds(), resolver), resolver), resolver);
+            } else {
+                return getRawType(resolvedType, resolver);
+            }
+        } else {
+            throw new IllegalArgumentException("Unsupported type " + type.getClass().getName());
+        }
+    }
+
+    private static class TypeVariableResolver {
+        private List<TypeVariableDeclaration> declarations = new ArrayList<TypeVariableDeclaration>();
+
+        private TypeVariableResolver(List<TypeVariableDeclaration> implementation) {
+            this.declarations = implementation;
+        }
+
+        public TypeVariableResolver(Class<?> subclass, Class<?> declaringClass) {
+            declarations.add(new TypeVariableDeclaration(subclass, subclass.getGenericSuperclass()));
+            while (declaringClass != subclass && declaringClass.isAssignableFrom(subclass)) {
+                subclass = subclass.getSuperclass();
+                declarations.add(new TypeVariableDeclaration(subclass, subclass.getGenericSuperclass()));
+            }
+        }
+
+        public Type resolve(TypeVariable<?> variable) {
+            if (declarations.size() < 2) {
+                return getRawType(variable.getBounds(), this);
+            }
+            int hierarchyIndex = declarations.size() - 1;
+            TypeVariableDeclaration typeVariableImplementation = declarations.get(hierarchyIndex);
+            TypeVariable<?>[] typeParameters = typeVariableImplementation.getDeclaredTypeParameters();
+            int typeIndex = -1;
+            for (int i = 0; i < typeParameters.length; i++) {
+                if (variable.getName().equals(typeParameters[i].getName())) {
+                    typeIndex = i;
+                    break;
+                }
+            }
+            if (typeIndex == -1) {
+                // type erasure
+                return Object.class;
+            }
+            TypeVariableDeclaration declaration = declarations.get(hierarchyIndex - 1);
+            Type genericClass = declaration.getAssignment();
+            if (genericClass instanceof ParameterizedType) {
+                ParameterizedType classType = (ParameterizedType) genericClass;
+                return resolveType(classType.getActualTypeArguments()[typeIndex], remove());
+            } else {
+                TypeVariable<?>[] typeVariables = declaration.getDeclaredTypeParameters();
+                if (typeVariables.length > typeIndex) {
+                    return resolveType(typeVariables[typeIndex], remove());
+                } else {
+                    return Object.class; //type erasure
+                }
+            }
+        }
+
+        public TypeVariableResolver remove() {
+            List<TypeVariableDeclaration> declarations = new ArrayList<TypeVariableDeclaration>(this.declarations);
+            declarations.remove(declarations.size() - 1);
+            return new TypeVariableResolver(declarations);
+        }
+    }
+
+    private static class TypeVariableDeclaration {
+        private Class<?> declaringClass;
+        private Type assignment;
+
+        public TypeVariableDeclaration(Class<?> declaringClass, Type assignment) {
+            this.declaringClass = declaringClass;
+            this.assignment = assignment;
+        }
+
+        public Type getAssignment() {
+            return assignment;
+        }
+
+        public TypeVariable<?>[] getDeclaredTypeParameters() {
+            return declaringClass.getTypeParameters();
+        }
+    }
+
+    private static Type getRawType(Type[] types, TypeVariableResolver resolver) {
+        Class<?>[] rawTypes = getRawTypes(types, resolver);
+        Class<?>[] classTypes = getClassTypes(rawTypes);
+        if (classTypes.length > 0) {
+            return getMostSpecificType(classTypes, types);
+        } else {
+            return getMostSpecificType(rawTypes, types);
+        }
+    }
+
+    private static class ParametrizedTypeImpl implements ParameterizedType {
+        private final Type owner;
+        private final Type rawType;
+        private final Type[] types;
+
+        public ParametrizedTypeImpl(Type owner, Type raw, Type... types) {
+            this.owner = owner;
+            this.rawType = raw;
+            this.types = types;
+        }
+
+        @Override
+        public Type[] getActualTypeArguments() {
+            return types.clone();
+        }
+
+        @Override
+        public Type getOwnerType() {
+            return owner;
+        }
+
+        @Override
+        public Type getRawType() {
+            return rawType;
+        }
+    }
+
+    private static Class<?>[] getClassTypes(Class<?>[] rawTypes) {
+        List<Class<?>> classTypes = new ArrayList<Class<?>>();
+        for (Class<?> rawType : rawTypes) {
+            if (!rawType.isInterface()) {
+                classTypes.add(rawType);
+            }
+        }
+        return classTypes.toArray(new Class[classTypes.size()]);
+    }
+}

Added: wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/spi/ConstraintViolationEntityFactory.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/spi/ConstraintViolationEntityFactory.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/spi/ConstraintViolationEntityFactory.java (added)
+++ wink/2.x/trunk/wink-bv-server/src/main/java/org/apache/wink/bv/server/spi/ConstraintViolationEntityFactory.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.wink.bv.server.spi;
+
+import javax.validation.ConstraintViolation;
+import javax.ws.rs.core.MediaType;
+import java.util.Set;
+
+/**
+ * Allows to create an entity in the format which can be handled by a {@link javax.ws.rs.ext.MessageBodyWriter}
+ * (This SPI is currently only for custom implementations -> no sorting based on a priority.)
+ */
+public interface ConstraintViolationEntityFactory {
+    boolean isResponsibleFor(MediaType mediaType);
+
+    Object createEntity(Set<ConstraintViolation<?>> constraintViolations);
+}

Added: wink/2.x/trunk/wink-bv-server/src/main/resources/META-INF/services/org.apache.wink.server.internal.validation.InvocationValidator
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/main/resources/META-INF/services/org.apache.wink.server.internal.validation.InvocationValidator?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/main/resources/META-INF/services/org.apache.wink.server.internal.validation.InvocationValidator (added)
+++ wink/2.x/trunk/wink-bv-server/src/main/resources/META-INF/services/org.apache.wink.server.internal.validation.InvocationValidator Thu Aug  8 16:17:04 2013
@@ -0,0 +1,20 @@
+#####################################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#####################################################################################
+
+org.apache.wink.bv.server.internal.validation.bv.BeanValidationInvocationValidator

Added: wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/BeanValidationIntegrationTest.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/BeanValidationIntegrationTest.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/BeanValidationIntegrationTest.java (added)
+++ wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/BeanValidationIntegrationTest.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.wink.test.bv.server.internal.validation.bv;
+
+import org.apache.wink.server.internal.servlet.MockServletInvocationTest;
+import org.apache.wink.test.mock.MockRequestConstructor;
+import org.junit.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+public class BeanValidationIntegrationTest extends MockServletInvocationTest {
+    private static final String GET = "GET";
+
+    private static final String BASE_PATH1 = "test1";
+    private static final String MISSING_METHOD_PARAMETER_VALUE_PATH = "missingMethodParameterValue";
+    private static final String RETURN_VALUE_VALIDATION_PATH = "returnValueValidation";
+
+    private static final String BASE_PATH2 = "test2";
+    private static final String MISSING_INJECTED_PARAMETER_VALUE_PATH = "missingInjectedParameterValue";
+
+    @Override
+    protected Class<?>[] getClasses() {
+        return new Class<?>[] {TestResource1.class, TestResource2.class};
+    }
+
+    @Path(BeanValidationIntegrationTest.BASE_PATH1)
+    public static class TestResource1 {
+        @GET
+        @Path(MISSING_METHOD_PARAMETER_VALUE_PATH)
+        @Produces(MediaType.TEXT_PLAIN)
+        public String parameterValidation(@NotNull @PathParam("missingMethodParameterValue") String missingValue) {
+            return null;
+        }
+
+        @GET
+        @Path(RETURN_VALUE_VALIDATION_PATH)
+        @Produces(MediaType.TEXT_PLAIN)
+
+        @NotNull
+        public String returnValueValidation() {
+            return null;
+        }
+    }
+
+    @Path(BeanValidationIntegrationTest.BASE_PATH2)
+    public static class TestResource2 {
+        @NotNull
+        @PathParam("missingInjectedParameterValue")
+        private String testParam;
+
+        @GET
+        @Path(MISSING_INJECTED_PARAMETER_VALUE_PATH)
+        @Produces(MediaType.TEXT_PLAIN)
+        public String injectedParameterValidation() {
+            return null;
+        }
+    }
+
+    @Test
+    public void testViolatedMethodParameterValue() throws Exception {
+        MockHttpServletRequest request =
+                MockRequestConstructor.constructMockRequest(GET, BASE_PATH1 + "/" + MISSING_METHOD_PARAMETER_VALUE_PATH, MediaType.TEXT_PLAIN);
+        MockHttpServletResponse response = invoke(request);
+        assertEquals(400, response.getStatus());
+        assertTrue(response.getContentAsString().contains("'parameterValidation.arg0'"));
+        assertTrue(response.getContentAsString().contains(" null "));
+    }
+
+    @Test
+    public void testViolatedReturnValue() throws Exception {
+        MockHttpServletRequest request =
+                MockRequestConstructor.constructMockRequest(GET, BASE_PATH1 + "/" + RETURN_VALUE_VALIDATION_PATH, MediaType.TEXT_PLAIN);
+        MockHttpServletResponse response = invoke(request);
+        assertEquals(500, response.getStatus());
+        assertTrue(response.getContentAsString().contains("'returnValueValidation.<return value>'"));
+        assertTrue(response.getContentAsString().contains(" null "));
+    }
+
+    @Test
+    public void testViolatedInjectedParameterValue() throws Exception {
+        MockHttpServletRequest request =
+                MockRequestConstructor.constructMockRequest(GET, BASE_PATH2 + "/" + MISSING_INJECTED_PARAMETER_VALUE_PATH, MediaType.TEXT_PLAIN);
+        MockHttpServletResponse response = invoke(request);
+        assertEquals(400, response.getStatus());
+        assertTrue(response.getContentAsString().contains("'testParam'"));
+        assertTrue(response.getContentAsString().contains(" null "));
+    }
+}

Added: wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/ValidateOnExecutionTest.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/ValidateOnExecutionTest.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/ValidateOnExecutionTest.java (added)
+++ wink/2.x/trunk/wink-bv-server/src/test/java/org/apache/wink/test/bv/server/internal/validation/bv/ValidateOnExecutionTest.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,490 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.wink.test.bv.server.internal.validation.bv;
+
+import junit.framework.Assert;
+import org.apache.wink.bv.server.internal.validation.bv.util.ReflectionUtils;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import javax.validation.executable.ExecutableType;
+import javax.validation.executable.ValidateOnExecution;
+import java.lang.reflect.Method;
+
+public class ValidateOnExecutionTest {
+
+    /*
+     * block #1
+     */
+    @Test
+    public void testNoAnnotation() throws NoSuchMethodException {
+        Method getterMethod = BaseWithoutAnnotation.class.getMethod("getSimple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+
+        Method simpleMethod = BaseWithoutAnnotation.class.getMethod("simple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+    }
+
+    @Test
+    public void testBaseWithMethodAnnotation() throws NoSuchMethodException {
+        Method getterMethod = BaseWithMethodAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+        Assert.assertEquals(ExecutableType.GETTER_METHODS, ReflectionUtils.extractValidateOnExecutionFrom(getterMethod).type()[0]);
+
+        Method simpleMethod = BaseWithMethodAnnotation.class.getMethod("simple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+        Assert.assertEquals(ExecutableType.ALL, ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod).type()[0]);
+    }
+
+    @Test
+    public void testBaseWithClassAnnotation() throws NoSuchMethodException {
+        Method getterMethod = BaseWithClassAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+
+        Method simpleMethod = BaseWithClassAnnotation.class.getMethod("simple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+    }
+
+    @Test
+    public void testBaseWithClassAndMethodAnnotation() throws NoSuchMethodException {
+        Method getterMethod = BaseWithClassAndMethodAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+        Assert.assertEquals(ExecutableType.GETTER_METHODS, ReflectionUtils.extractValidateOnExecutionFrom(getterMethod).type()[0]);
+
+        Method simpleMethod = BaseWithClassAndMethodAnnotation.class.getMethod("simple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+        Assert.assertEquals(ExecutableType.ALL, ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod).type()[0]);
+    }
+
+    /*
+     * block #2
+     */
+    @Test
+    public void testSubOfNoAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubOfBaseWithoutAnnotation.class.getMethod("getSimple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+
+        Method simpleMethod = SubOfBaseWithoutAnnotation.class.getMethod("simple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+    }
+
+    @Test
+    public void testSubOfBaseWithMethodAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubOfBaseWithMethodAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+        Assert.assertEquals(ExecutableType.GETTER_METHODS, ReflectionUtils.extractValidateOnExecutionFrom(getterMethod).type()[0]);
+
+        Method simpleMethod = SubOfBaseWithMethodAnnotation.class.getMethod("simple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+        Assert.assertEquals(ExecutableType.ALL, ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod).type()[0]);
+    }
+
+    @Test
+    public void testSubOfBaseWithClassAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubOfBaseWithClassAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+
+        Method simpleMethod = SubOfBaseWithClassAnnotation.class.getMethod("simple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+    }
+
+    @Test
+    public void testSubOfBaseWithClassAndMethodAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubOfBaseWithClassAndMethodAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+        Assert.assertEquals(ExecutableType.GETTER_METHODS, ReflectionUtils.extractValidateOnExecutionFrom(getterMethod).type()[0]);
+
+        Method simpleMethod = SubOfBaseWithClassAndMethodAnnotation.class.getMethod("simple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+        Assert.assertEquals(ExecutableType.ALL, ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod).type()[0]);
+    }
+
+    /*
+     * block #3
+     */
+    @Test
+    public void testSubWithOverridingOfNoAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubWithOverridingOfBaseWithoutAnnotation.class.getMethod("getSimple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+
+        Method simpleMethod = SubWithOverridingOfBaseWithoutAnnotation.class.getMethod("simple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+    }
+
+    @Test
+    public void testSubWithOverridingOfBaseWithMethodAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubWithOverridingOfBaseWithMethodAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+        Assert.assertEquals(ExecutableType.GETTER_METHODS, ReflectionUtils.extractValidateOnExecutionFrom(getterMethod).type()[0]);
+
+        Method simpleMethod = SubWithOverridingOfBaseWithMethodAnnotation.class.getMethod("simple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+        Assert.assertEquals(ExecutableType.ALL, ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod).type()[0]);
+    }
+
+    @Test
+    public void testSubWithOverridingOfBaseWithClassAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubWithOverridingOfBaseWithClassAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+
+        Method simpleMethod = SubWithOverridingOfBaseWithClassAnnotation.class.getMethod("simple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+    }
+
+    @Test
+    public void testSubWithOverridingOfBaseWithClassAndMethodAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubWithOverridingOfBaseWithClassAndMethodAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+        Assert.assertEquals(ExecutableType.GETTER_METHODS, ReflectionUtils.extractValidateOnExecutionFrom(getterMethod).type()[0]);
+
+        Method simpleMethod = SubWithOverridingOfBaseWithClassAndMethodAnnotation.class.getMethod("simple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+        Assert.assertEquals(ExecutableType.ALL, ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod).type()[0]);
+    }
+
+    /*
+     * block #4
+     */
+    @Test
+    public void testOverriddenMethodsWithIgnoredAnnotations() throws NoSuchMethodException {
+        Method getterMethod = OverriddenWithAnnotations.class.getMethod("getSimple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+
+        Method simpleMethod = OverriddenWithAnnotations.class.getMethod("simple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+    }
+
+    /*
+     * block #5
+     */
+    @Test
+    public void testSubOfGenericOverriddenWithClassMethod() throws NoSuchMethodException {
+        Method getterMethod = SubOfGenericOverriddenWithMethodAnnotation.class.getMethod("getSimple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod)); //generic method has no annotation
+    }
+
+    @Test
+    public void testSubOfGenericOverriddenWithClassAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubOfGenericOverriddenWithClassAnnotation.class.getMethod("getSimple");
+        Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod)); //class with generic method has no annotation
+    }
+
+    @Test
+    public void testSubOfGenericBaseWithMethodAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubOfGenericBaseWithMethodAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+    }
+
+    @Test
+    public void testSubOfGenericBaseWithClassAnnotation() throws NoSuchMethodException {
+        Method getterMethod = SubOfGenericBaseWithClassAnnotation.class.getMethod("getSimple");
+        Assert.assertNotNull(ReflectionUtils.extractValidateOnExecutionFrom(getterMethod));
+    }
+
+    /*
+     * block #6 //TODO currently not implemented
+     */
+    @Ignore
+    @Test
+    public void testInvalidOverriddenWithMethodAnnotations() throws NoSuchMethodException {
+        RuntimeException result = null;
+        try {
+            Method getterMethod = InvalidOverriddenWithMethodAnnotations.class.getMethod("getSimple");
+            ReflectionUtils.extractValidateOnExecutionFrom(getterMethod);
+        } catch (RuntimeException e) {
+            result = e;
+        }
+
+        Assert.assertNotNull(result);
+        result = null;
+
+        try {
+            Method simpleMethod = InvalidOverriddenWithMethodAnnotations.class.getMethod("simple");
+            Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+
+        } catch (RuntimeException e) {
+            result = e;
+        }
+
+        Assert.assertNotNull(result);
+        result = null;
+
+        try {
+            Method simpleMethod = InvalidSubOfGenericBaseWithMethodAnnotation.class.getMethod("getSimple");
+            Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+
+        } catch (RuntimeException e) {
+            result = e;
+        }
+
+        Assert.assertNotNull(result);
+    }
+
+    @Ignore
+    @Test
+    public void testInvalidOverriddenWithClassAnnotations() throws NoSuchMethodException {
+        RuntimeException result = null;
+        try {
+            Method getterMethod = InvalidOverriddenWithClassAnnotations.class.getMethod("getSimple");
+            ReflectionUtils.extractValidateOnExecutionFrom(getterMethod);
+        } catch (RuntimeException e) {
+            result = e;
+        }
+
+        Assert.assertNotNull(result);
+        result = null;
+
+        try {
+            Method simpleMethod = InvalidOverriddenWithClassAnnotations.class.getMethod("simple");
+            Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+
+        } catch (RuntimeException e) {
+            result = e;
+        }
+
+        Assert.assertNotNull(result);
+        result = null;
+
+        try {
+            Method simpleMethod = InvalidSubOfGenericBaseWithClassAnnotation.class.getMethod("getSimple");
+            Assert.assertNull(ReflectionUtils.extractValidateOnExecutionFrom(simpleMethod));
+
+        } catch (RuntimeException e) {
+            result = e;
+        }
+
+        Assert.assertNotNull(result);
+    }
+
+    private class BaseWithoutAnnotation {
+        public int getSimple() {
+            return 0;
+        }
+
+        public void simple() {
+        }
+    }
+
+    private class BaseWithMethodAnnotation {
+        //just one of the values to check if the correct annotation instance gets returned
+        @ValidateOnExecution(type = ExecutableType.GETTER_METHODS)
+        public int getSimple() {
+            return 0;
+        }
+
+        //just one of the values to check if the correct annotation instance gets returned
+        @ValidateOnExecution(type = ExecutableType.ALL)
+        public void simple() {
+        }
+    }
+
+    @ValidateOnExecution
+    private class BaseWithClassAnnotation {
+        public int getSimple() {
+            return 0;
+        }
+
+        public void simple() {
+        }
+    }
+
+    //just one of the values to check if the correct annotation instance gets returned
+    @ValidateOnExecution(type = ExecutableType.GETTER_METHODS)
+    private class BaseWithClassAndMethodAnnotation {
+        public int getSimple() {
+            return 0;
+        }
+
+        //just one of the values to check if the correct annotation instance gets returned
+        @ValidateOnExecution(type = ExecutableType.ALL)
+        public void simple() {
+        }
+    }
+
+    private class SubOfBaseWithoutAnnotation extends BaseWithoutAnnotation {
+    }
+
+    private class SubOfBaseWithMethodAnnotation extends BaseWithMethodAnnotation
+    {
+    }
+
+    private class SubOfBaseWithClassAnnotation extends BaseWithClassAnnotation
+    {
+    }
+
+    private class SubOfBaseWithClassAndMethodAnnotation extends BaseWithClassAndMethodAnnotation
+    {
+    }
+
+    private class SubWithOverridingOfBaseWithoutAnnotation extends BaseWithoutAnnotation {
+        @Override
+        public int getSimple() {
+            return super.getSimple();
+        }
+
+        @Override
+        public void simple() {
+            super.simple();
+        }
+    }
+
+    private class SubWithOverridingOfBaseWithMethodAnnotation extends BaseWithMethodAnnotation {
+        @Override
+        public int getSimple() {
+            return super.getSimple();
+        }
+
+        @Override
+        public void simple() {
+            super.simple();
+        }
+    }
+
+    private class SubWithOverridingOfBaseWithClassAnnotation extends BaseWithClassAnnotation {
+        @Override
+        public int getSimple() {
+            return super.getSimple();
+        }
+
+        @Override
+        public void simple() {
+            super.simple();
+        }
+    }
+
+    private class SubWithOverridingOfBaseWithClassAndMethodAnnotation extends BaseWithClassAndMethodAnnotation {
+        @Override
+        public int getSimple() {
+            return super.getSimple();
+        }
+
+        @Override
+        public void simple() {
+            super.simple();
+        }
+    }
+
+    @ValidateOnExecution
+    private class OverriddenWithAnnotations extends BaseWithoutAnnotation {
+        @Override
+        public int getSimple() {
+            return super.getSimple();
+        }
+
+        @ValidateOnExecution
+        @Override
+        public void simple() {
+            super.simple();
+        }
+    }
+
+    private class InvalidOverriddenWithMethodAnnotations extends BaseWithMethodAnnotation {
+        @ValidateOnExecution
+        @Override
+        public int getSimple() {
+            return super.getSimple();
+        }
+
+        @ValidateOnExecution
+        @Override
+        public void simple() {
+            super.simple();
+        }
+    }
+
+    @ValidateOnExecution
+    private class InvalidOverriddenWithClassAnnotations extends BaseWithClassAnnotation {
+        @Override
+        public int getSimple() {
+            return super.getSimple();
+        }
+
+        @Override
+        public void simple() {
+            super.simple();
+        }
+    }
+
+    private class GenericBaseWithoutAnnotation<T> {
+        public T getSimple() {
+            return null;
+        }
+    }
+
+    private class SubOfGenericOverriddenWithMethodAnnotation extends GenericBaseWithoutAnnotation<Integer> {
+        @ValidateOnExecution
+        @Override
+        public Integer getSimple() {
+            return super.getSimple();
+        }
+    }
+
+    @ValidateOnExecution
+    private class SubOfGenericOverriddenWithClassAnnotation extends GenericBaseWithoutAnnotation<Integer> {
+        @Override
+        public Integer getSimple() {
+            return super.getSimple();
+        }
+    }
+
+    private class GenericBaseWithMethodAnnotation<T> {
+        @ValidateOnExecution
+        public T getSimple() {
+            return null;
+        }
+    }
+
+    private class SubOfGenericBaseWithMethodAnnotation<T> extends GenericBaseWithMethodAnnotation<Integer> {
+        @Override
+        public Integer getSimple() {
+            return null;
+        }
+    }
+
+    @ValidateOnExecution
+    private class GenericBaseWithClassAnnotation<T> {
+        public T getSimple() {
+            return null;
+        }
+    }
+
+    private class SubOfGenericBaseWithClassAnnotation extends GenericBaseWithMethodAnnotation<Integer> {
+        @Override
+        public Integer getSimple() {
+            return null;
+        }
+    }
+
+    private class InvalidSubOfGenericBaseWithMethodAnnotation<T> extends GenericBaseWithMethodAnnotation<Integer> {
+        @ValidateOnExecution
+        @Override
+        public Integer getSimple() {
+            return null;
+        }
+    }
+
+    @ValidateOnExecution
+    private class InvalidSubOfGenericBaseWithClassAnnotation extends GenericBaseWithClassAnnotation<Integer> {
+        @Override
+        public Integer getSimple() {
+            return null;
+        }
+    }
+}

Added: wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/BootstrappingContext.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/BootstrappingContext.java?rev=1511849&view=auto
==============================================================================
--- wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/BootstrappingContext.java (added)
+++ wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/BootstrappingContext.java Thu Aug  8 16:17:04 2013
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.wink.server.internal;
+
+import org.apache.wink.common.internal.runtime.AbstractRuntimeContext;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class BootstrappingContext extends AbstractRuntimeContext {
+    @Override
+    public InputStream getInputStream() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public OutputStream getOutputStream() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+}

Modified: wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java
URL: http://svn.apache.org/viewvc/wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java?rev=1511849&r1=1511848&r2=1511849&view=diff
==============================================================================
--- wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java (original)
+++ wink/2.x/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java Thu Aug  8 16:17:04 2013
@@ -19,26 +19,8 @@
  *******************************************************************************/
 package org.apache.wink.server.internal;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.Map.Entry;
-
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Application;
-
 import org.apache.commons.lang.ClassUtils;
+import org.apache.wink.common.RuntimeContext;
 import org.apache.wink.common.internal.WinkConfiguration;
 import org.apache.wink.common.internal.application.ApplicationValidator;
 import org.apache.wink.common.internal.i18n.Messages;
@@ -74,9 +56,29 @@ import org.apache.wink.server.internal.l
 import org.apache.wink.server.internal.log.Responses;
 import org.apache.wink.server.internal.registry.ResourceRegistry;
 import org.apache.wink.server.internal.registry.ServerInjectableFactory;
+import org.apache.wink.server.internal.validation.InvocationValidator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Application;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.ServiceLoader;
+import java.util.Set;
+
 /**
  * <p>
  * This class implements a default deployment configuration for Wink. In order
@@ -142,6 +144,8 @@ public class DeploymentConfiguration imp
 
     private boolean                   isDefaultResponseCharset            = false;
 
+    private InvocationValidator invocationValidator;
+
     /**
      * Makes sure that the object was properly initialized. Should be invoked
      * AFTER all the setters were invoked.
@@ -167,6 +171,7 @@ public class DeploymentConfiguration imp
         initAlternateShortcutMap();
         initMediaTypeMapper();
         initHandlers();
+        initInvocationValidator();
 
         // this next code is to dump the config to trace after initialization
         if (logger.isDebugEnabled()) {
@@ -706,4 +711,32 @@ public class DeploymentConfiguration imp
     public Set<ObjectFactory<?>> getApplicationObjectFactories() {
         return appObjectFactories;
     }
+
+    protected void initInvocationValidator() {
+
+        RuntimeContext bootstrappingContext = new BootstrappingContext();
+        for (InvocationValidator currentValidator : ServiceLoader.load(InvocationValidator.class)) {
+            if (invocationValidator != null) {
+                throw new IllegalStateException("It isn't supported to use multiple implementations of " +
+                        InvocationValidator.class.getName() + ". Found implementations: " +
+                        this.invocationValidator.getClass().getName() + " and " +
+                        currentValidator.getClass().getName());
+            }
+            if (currentValidator.init(bootstrappingContext, ofFactoryRegistry, providersRegistry)) {
+                invocationValidator = currentValidator;
+            }
+        }
+
+        if (invocationValidator == null) {
+            invocationValidator = getDefaultInvocationValidator();
+        }
+    }
+
+    protected InvocationValidator getDefaultInvocationValidator() {
+        return null;
+    }
+
+    public InvocationValidator getInvocationValidator() {
+        return invocationValidator;
+    }
 }



Mime
View raw message