package org.etk.core.rest.impl; import java.lang.annotation.Annotation; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.List; import javax.ws.rs.DefaultValue; import javax.ws.rs.Encoded; import javax.ws.rs.MatrixParam; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import javax.ws.rs.ext.Provider; import org.etk.common.logging.Logger; import org.etk.core.rest.FieldInjector; import org.etk.core.rest.impl.method.ParameterHelper; import org.etk.core.rest.impl.method.ParameterResolver; import org.etk.core.rest.impl.method.ParameterResolverFactory; import org.etk.core.rest.resource.ResourceDescriptorVisitor; public class FieldInjectorImpl implements FieldInjector { /** * Logger. */ private static final Logger LOG = Logger.getLogger(FieldInjectorImpl.class); /** * All annotations including JAX-RS annotation. */ private final Annotation[] annotations; /** * JAX-RS annotation. */ private final Annotation annotation; /** * Parameter type. See {@link Constructor#getGenericParameterTypes()} . */ private final Type type; /** * Parameter class. See {@link Constructor#getParameterTypes()} */ private final Class<?> clazz; /** * Default value for this parameter, default value can be used if there is not * found required parameter in request. See {@link javax.ws.rs.DefaultValue}. */ private final String defaultValue; /** * See {@link javax.ws.rs.Encoded}. */ private final boolean encoded; /** * Field name, see {@link java.lang.reflect.Field#getName()}. */ private final String name; /** * @param resourceClass class that contains field <tt>jfield</tt> * @param jfield java.lang.reflect.Field */ public FieldInjectorImpl(Class<?> resourceClass, java.lang.reflect.Field jfield) { this.name = jfield.getName(); this.annotations = jfield.getDeclaredAnnotations(); this.clazz = jfield.getType(); this.type = jfield.getGenericType(); Annotation annotation = null; String defaultValue = null; boolean encoded = false; // is resource provider boolean provider = resourceClass.getAnnotation(Provider.class) != null; List<String> allowedAnnotation; if (provider) allowedAnnotation = ParameterHelper.PROVIDER_FIELDS_ANNOTATIONS; else allowedAnnotation = ParameterHelper.RESOURCE_FIELDS_ANNOTATIONS; for (Annotation a : annotations) { Class<?> ac = a.annotationType(); if (allowedAnnotation.contains(ac.getName())) { if (annotation == null) { annotation = a; } else { String msg = "JAX-RS annotations on one of fields are equivocality. Annotations: " + annotation.toString() + " and " + a.toString() + " can't be applied to one field."; throw new RuntimeException(msg); } // @Encoded has not sense for Provider. Provider may use only @Context // annotation for fields } else if (ac == Encoded.class && !provider) { encoded = true; // @Default has not sense for Provider. Provider may use only @Context // annotation for fields } else if (ac == DefaultValue.class && !provider) { defaultValue = ((DefaultValue) a).value(); } else { LOG.warn("Field " + jfield.toString() + " contains unknown or not allowed JAX-RS annotation " + a.toString() + ". It will be ignored."); } } this.defaultValue = defaultValue; this.annotation = annotation; this.encoded = encoded || resourceClass.getAnnotation(Encoded.class) != null; } /** * {@inheritDoc} */ public Annotation getAnnotation() { return annotation; } /** * {@inheritDoc} */ public Annotation[] getAnnotations() { return annotations; } /** * {@inheritDoc} */ public String getDefaultValue() { return defaultValue; } /** * {@inheritDoc} */ public Class<?> getParameterClass() { return clazz; } /** * {@inheritDoc} */ public Type getGenericType() { return type; } /** * {@inheritDoc} */ public boolean isEncoded() { return encoded; } /** * {@inheritDoc} */ public String getName() { return name; } /** * {@inheritDoc} */ public void inject(Object resource, ApplicationContext context) { if (annotation != null) { ParameterResolver<?> pr = ParameterResolverFactory.createParameterResolver(annotation); try { java.lang.reflect.Field jfield = resource.getClass().getDeclaredField(getName()); if (!Modifier.isPublic(jfield.getModifiers())) jfield.setAccessible(true); jfield.set(resource, pr.resolve(this, context)); } catch (Throwable e) { // if (LOG.isDebugEnabled()) e.printStackTrace(); Class<?> ac = annotation.annotationType(); if (ac == MatrixParam.class || ac == QueryParam.class || ac == PathParam.class) throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).build()); } } } /** * {@inheritDoc} */ public void accept(ResourceDescriptorVisitor visitor) { visitor.visitFieldInjector(this); } /** * {@inheritDoc} */ @Override public String toString() { StringBuffer sb = new StringBuffer("[ FieldInjectorImpl: "); sb.append("annotation: " + getAnnotation()) .append("; type: " + getParameterClass()) .append("; generic-type : " + getGenericType()) .append("; default-value: " + getDefaultValue()) .append("; encoded: " + isEncoded()) .append(" ]"); return sb.toString(); } }