You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wink.apache.org by gp...@apache.org on 2013/08/08 18:17:06 UTC
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...
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;
+ }
}