diff --git a/impl/src/main/java/org/jboss/seam/rest/validation/ValidatedMethodMetadata.java b/impl/src/main/java/org/jboss/seam/rest/validation/ValidatedMethodMetadata.java
new file mode 100644
index 0000000..b268992
--- /dev/null
+++ b/impl/src/main/java/org/jboss/seam/rest/validation/ValidatedMethodMetadata.java
@@ -0,0 +1,66 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.rest.validation;
+
+import java.lang.reflect.Method;
+import java.util.Set;
+
+/**
+ * Caches method metadata needed to perform validation of JAX-RS requests.
+ * @author Jozef Hartinger
+ *
+ */
+public class ValidatedMethodMetadata
+{
+ private final Method method;
+ private final Integer messageBody; // position of the messageBody, may be null
+ private final Set parameterObjects; // positions of parameter objects
+ private final ValidateRequest interceptorBinding;
+
+ public ValidatedMethodMetadata(Method method, Integer messageBody, Set parameterObjects, ValidateRequest interceptorBinding)
+ {
+ this.method = method;
+ this.messageBody = messageBody;
+ this.parameterObjects = parameterObjects;
+ this.interceptorBinding = interceptorBinding;
+ }
+
+ public Method getMethod()
+ {
+ return method;
+ }
+
+ public Integer getMessageBody()
+ {
+ return messageBody;
+ }
+
+ public Set getParameterObjects()
+ {
+ return parameterObjects;
+ }
+
+ public ValidateRequest getInterceptorBinding()
+ {
+ return interceptorBinding;
+ }
+}
diff --git a/impl/src/main/java/org/jboss/seam/rest/validation/ValidationInterceptor.java b/impl/src/main/java/org/jboss/seam/rest/validation/ValidationInterceptor.java
index 24148f0..e82c1d0 100644
--- a/impl/src/main/java/org/jboss/seam/rest/validation/ValidationInterceptor.java
+++ b/impl/src/main/java/org/jboss/seam/rest/validation/ValidationInterceptor.java
@@ -23,6 +23,7 @@
import java.io.Serializable;
import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
@@ -51,59 +52,97 @@ public class ValidationInterceptor implements Serializable
@Inject
private Validator validator;
+ @Inject
+ private ValidationMetadata metadata;
@AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception
{
- log.debugv("Intercepting {0}", ctx.getMethod().toGenericString());
+ log.infov("Validating {0}", ctx.getMethod().toGenericString()); // TODO
+
+ // do scanning only once
+ if (! metadata.containsMethodMetadata(ctx.getMethod()))
+ {
+ scanMethod(ctx.getMethod());
+ }
Set> violations = new HashSet>();
- ValidateRequest interceptorBinding = getInterceptorBinding(ctx);
+ ValidatedMethodMetadata method = metadata.getMethodMetadata(ctx.getMethod());
+ ValidateRequest interceptorBinding = method.getInterceptorBinding();
Class>[] groups = interceptorBinding.groups();
-
+
// validate JAX-RS resource fields
if (interceptorBinding.validateResourceFields())
{
+ log.infov("Validating JAX-RS resource {0}", ctx.getTarget()); // TODO
violations.addAll(validator.validate(ctx.getTarget(), groups));
}
- Annotation[][] parameterAnnotations = ctx.getMethod().getParameterAnnotations();
- for (int i = 0; i < parameterAnnotations.length; i++)
+ // validate message body
+ if (interceptorBinding.validateMessageBody() && (method.getMessageBody() != null))
{
- if (interceptorBinding.validateMessageBody() && parameterAnnotations[i].length == 0)
- {
- log.debugv("Validating HTTP message body {0}", ctx.getParameters()[i]);
- // entity body
- violations.addAll(validator.validate(ctx.getParameters()[i], groups));
- }
-
- if (interceptorBinding.validateParameterObjects() && isParameterObject(ctx.getMethod().getParameterTypes()[i], ctx.getMethod().getParameterAnnotations()[i]))
+ Object parameter = ctx.getParameters()[method.getMessageBody()];
+ log.infov("Validating HTTP message body {0}", parameter); // TODO
+ violations.addAll(validator.validate(parameter, groups));
+ }
+
+ // validate parameter objects
+ if (interceptorBinding.validateParameterObjects())
+ {
+ for (Integer parameterIndex : method.getParameterObjects())
{
- // parameter objects
- log.debugv("Validating parameter object {0}", ctx.getParameters()[i]);
- violations.addAll(validator.validate(ctx.getParameters()[i], groups));
+ Object parameter = ctx.getParameters()[parameterIndex];
+ log.infov("Validating parameter object {0}", parameter); // TODO
+ violations.addAll(validator.validate(parameter, groups));
}
}
-
+
if (violations.isEmpty())
{
- log.debug("Validation completed. No violations found.");
+ log.info("Validation completed. No violations found."); // TODO
return ctx.proceed();
}
else
{
- log.debugv("Validation completed. {0} violations found.", violations.size());
+ log.infov("Validation completed. {0} violations found.", violations.size()); // TODO
throw new ValidationException(violations);
}
}
+
+ private void scanMethod(Method method)
+ {
+ Integer messageBodyIndex = null;
+ Set parameterObjects = new HashSet();
+ ValidateRequest interceptorBinding = getInterceptorBinding(method);
+
+ log.infov("This is the first time {0} is invoked. Scanning.", method); // TODO
+
+ Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+ for (int i = 0; i < parameterAnnotations.length; i++)
+ {
+ if (parameterAnnotations[i].length == 0)
+ {
+ log.infov("{0} identified as the message body.", method.getParameterTypes()[i]); // TODO
+ messageBodyIndex = i;
+ continue;
+ }
+
+ if (isParameterObject(method.getParameterTypes()[i], method.getParameterAnnotations()[i]))
+ {
+ log.infov("{0} identified as the parameter object.", method.getParameterTypes()[i]);
+ parameterObjects.add(i);
+ }
+ }
+ metadata.addMethodMetadata(new ValidatedMethodMetadata(method, messageBodyIndex, parameterObjects, interceptorBinding));
+ }
- private ValidateRequest getInterceptorBinding(InvocationContext ctx)
+ private ValidateRequest getInterceptorBinding(Method method)
{
- ValidateRequest interceptorBinding = Annotations.getAnnotation(ctx.getMethod(), ValidateRequest.class);
+ ValidateRequest interceptorBinding = Annotations.getAnnotation(method, ValidateRequest.class);
if (interceptorBinding == null)
{
- log.debugv("Unable to find @ValidateRequest interceptor binding for {0}", ctx.getMethod().toGenericString());
+ log.debugv("Unable to find @ValidateRequest interceptor binding for {0}", method.toGenericString());
// There is no @Validate on the method
// The interceptor is probably bound to the bean by @Interceptors
// annotation
@@ -124,7 +163,7 @@ private boolean isParameterObject(Class> parameterType, Annotation[] annotatio
}
// primitive type parameters are definitely not form objects
- if (parameterType.isPrimitive() || isPrimitiveWrapper(parameterType))
+ if (parameterType.isPrimitive() || isPrimitiveWrapper(parameterType) || String.class.isAssignableFrom(parameterType))
{
return false;
}
diff --git a/impl/src/main/java/org/jboss/seam/rest/validation/ValidationMetadata.java b/impl/src/main/java/org/jboss/seam/rest/validation/ValidationMetadata.java
new file mode 100644
index 0000000..d254b74
--- /dev/null
+++ b/impl/src/main/java/org/jboss/seam/rest/validation/ValidationMetadata.java
@@ -0,0 +1,54 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.rest.validation;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.enterprise.context.ApplicationScoped;
+
+/**
+ * Container for {@link ValidatedMethodMetadata}.
+ * @author Jozef Hartinger
+ *
+ */
+@ApplicationScoped
+public class ValidationMetadata
+{
+ private Map methods = new HashMap();
+
+ public ValidatedMethodMetadata getMethodMetadata(Method method)
+ {
+ return methods.get(method);
+ }
+
+ void addMethodMetadata(ValidatedMethodMetadata method)
+ {
+ methods.put(method.getMethod(), method);
+ }
+
+ public boolean containsMethodMetadata(Method method)
+ {
+ return methods.containsKey(method);
+ }
+}
diff --git a/impl/src/test/java/org/jboss/seam/rest/test/validation/FormObject.java b/impl/src/test/java/org/jboss/seam/rest/test/validation/FormObject.java
index ff1eb03..36423cc 100644
--- a/impl/src/test/java/org/jboss/seam/rest/test/validation/FormObject.java
+++ b/impl/src/test/java/org/jboss/seam/rest/test/validation/FormObject.java
@@ -21,6 +21,10 @@
*/
package org.jboss.seam.rest.test.validation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
@interface FormObject
{