From b3eb3e5f7361ce06943d46237bc46875344d6ea6 Mon Sep 17 00:00:00 2001 From: Roy Teeuwen Date: Fri, 13 Oct 2017 20:55:55 +0200 Subject: [PATCH] Made it possible to inject request parameters in a model and to adapt from a request immediatly instead of using request.getResource(). This way you could adapt your request in a servlet to a model with request parameters as fields. --- .../adapter/AdapterFactoryManager.java | 3 +- .../internal/adapter/SliceAdapterFactory.java | 13 ++- .../mapper/annotation/RequestParameter.java | 56 +++++++++++++ .../cognifide/slice/mapper/MapperBuilder.java | 4 + .../processor/RequestParameterProcessor.java | 79 +++++++++++++++++++ .../impl/AnnotatedFieldMapperStrategy.java | 6 +- 6 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 slice-mapper-api/src/main/java/com/cognifide/slice/mapper/annotation/RequestParameter.java create mode 100644 slice-mapper/src/main/java/com/cognifide/slice/mapper/impl/processor/RequestParameterProcessor.java diff --git a/slice-core/src/main/java/com/cognifide/slice/core/internal/adapter/AdapterFactoryManager.java b/slice-core/src/main/java/com/cognifide/slice/core/internal/adapter/AdapterFactoryManager.java index 817d5660..5bb3df7d 100644 --- a/slice-core/src/main/java/com/cognifide/slice/core/internal/adapter/AdapterFactoryManager.java +++ b/slice-core/src/main/java/com/cognifide/slice/core/internal/adapter/AdapterFactoryManager.java @@ -31,6 +31,7 @@ import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Service; +import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.adapter.AdapterFactory; import org.apache.sling.api.resource.Resource; import org.osgi.framework.Bundle; @@ -145,7 +146,7 @@ private ServiceRegistration createAdapterFactory(Collection> classes, S SliceAdapterFactory factory = new SliceAdapterFactory(name); Dictionary properties = new Hashtable(); - properties.put(AdapterFactory.ADAPTABLE_CLASSES, new String[] { Resource.class.getName() }); + properties.put(AdapterFactory.ADAPTABLE_CLASSES, new String[] { Resource.class.getName(), SlingHttpServletRequest.class.getName() }); properties.put(AdapterFactory.ADAPTER_CLASSES, adapterClassNames); return bundleContext.registerService(AdapterFactory.class.getName(), factory, properties); } diff --git a/slice-core/src/main/java/com/cognifide/slice/core/internal/adapter/SliceAdapterFactory.java b/slice-core/src/main/java/com/cognifide/slice/core/internal/adapter/SliceAdapterFactory.java index b4783fee..bc212471 100644 --- a/slice-core/src/main/java/com/cognifide/slice/core/internal/adapter/SliceAdapterFactory.java +++ b/slice-core/src/main/java/com/cognifide/slice/core/internal/adapter/SliceAdapterFactory.java @@ -20,6 +20,7 @@ package com.cognifide.slice.core.internal.adapter; +import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.adapter.AdapterFactory; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; @@ -47,10 +48,16 @@ public SliceAdapterFactory(String injectorName) { @Override public AdapterType getAdapter(Object adaptable, Class type) { - if (!(adaptable instanceof Resource)) { + if (!((adaptable instanceof Resource) || (adaptable instanceof SlingHttpServletRequest))) { return null; } - Resource resource = (Resource) adaptable; + + Resource resource; + if(adaptable instanceof Resource) { + resource = (Resource) adaptable; + } else { + resource = ((SlingHttpServletRequest) adaptable).getResource(); + } InjectorWithContext injector = getInjector(resource); if (injector != null) { @@ -67,7 +74,7 @@ public AdapterType getAdapter(Object adaptable, Class } } - private InjectorWithContext getInjector(Resource resource) { + private InjectorWithContext getInjector(Resource resource) { ResourceResolver resourceResolver = resource.getResourceResolver(); InjectorsRepository repository = resourceResolver.adaptTo(InjectorsRepository.class); if (repository == null) { diff --git a/slice-mapper-api/src/main/java/com/cognifide/slice/mapper/annotation/RequestParameter.java b/slice-mapper-api/src/main/java/com/cognifide/slice/mapper/annotation/RequestParameter.java new file mode 100644 index 00000000..202d5512 --- /dev/null +++ b/slice-mapper-api/src/main/java/com/cognifide/slice/mapper/annotation/RequestParameter.java @@ -0,0 +1,56 @@ +/*- + * #%L + * Slice - Mapper API + * %% + * Copyright (C) 2012 Cognifide Limited + * %% + * Licensed 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. + * #L% + */ +package com.cognifide.slice.mapper.annotation; + +import java.lang.annotation.*; + +/** + * Indicates that a given field should be mapped from a request parameter . The + * name of the request parameter is indicated by the name of the field or value of {@link RequestParameter} (if + * specified). Only a type of string is allowed + * Example: + * + *
+ * {@literal @}SliceResource
+ * public class ExampleModel {
+ *
+ *   {@literal @}RequestParameter
+ *   private String myParameter;
+ *
+ *   {@literal @}RequestParameter("second-parameter")
+ *   private String secondParameter;
+ * }
+ * 
+ * + * @author roy.teeuwen + * + */ +@Documented +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface RequestParameter { + + /** + * Custom request parameter name. If empty, property name is read from field's name. + * + * @return value + */ + String value() default ""; +} diff --git a/slice-mapper/src/main/java/com/cognifide/slice/mapper/MapperBuilder.java b/slice-mapper/src/main/java/com/cognifide/slice/mapper/MapperBuilder.java index ad77dc15..be69272a 100644 --- a/slice-mapper/src/main/java/com/cognifide/slice/mapper/MapperBuilder.java +++ b/slice-mapper/src/main/java/com/cognifide/slice/mapper/MapperBuilder.java @@ -62,6 +62,9 @@ public final class MapperBuilder { @Inject private RequestAttributeProcessor requestAttributeProcessor; + @Inject + private RequestParameterProcessor requestParameterProcessor; + @Inject private CustomProcessorsCollector customProcessorsCollector; @@ -118,6 +121,7 @@ public MapperBuilder addSliceProcessors() { processors.add(sliceResourceFieldProcessor); // @SliceResource processors.add(childrenFieldProcessor); // child models @Children processors.add(requestAttributeProcessor); // @RequestAttribute + processors.add(requestParameterProcessor); // @RequestParameter processors.add(new ListFieldProcessor()); // Subclasses of Collection and arrays processors.add(new BooleanFieldProcessor()); // booleans processors.add(new EnumFieldProcessor()); // enums diff --git a/slice-mapper/src/main/java/com/cognifide/slice/mapper/impl/processor/RequestParameterProcessor.java b/slice-mapper/src/main/java/com/cognifide/slice/mapper/impl/processor/RequestParameterProcessor.java new file mode 100644 index 00000000..3afb951c --- /dev/null +++ b/slice-mapper/src/main/java/com/cognifide/slice/mapper/impl/processor/RequestParameterProcessor.java @@ -0,0 +1,79 @@ +/*- + * #%L + * Slice - Mapper + * %% + * Copyright (C) 2012 Cognifide Limited + * %% + * Licensed 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. + * #L% + */ +package com.cognifide.slice.mapper.impl.processor; + +import com.cognifide.slice.mapper.annotation.RequestParameter; +import com.cognifide.slice.mapper.api.processor.FieldProcessor; +import com.google.inject.Inject; +import org.apache.commons.lang.StringUtils; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ValueMap; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class RequestParameterProcessor implements FieldProcessor { + + @Inject + private SlingHttpServletRequest slingRequest; + + @Override + public boolean accepts(final Resource resource, final Field field) { + Class fieldType = field.getType(); + return (Collection.class.isAssignableFrom(fieldType) || fieldType.equals(String.class)) && field.isAnnotationPresent(RequestParameter.class); + } + + @Override + public Object mapResourceToField(Resource resource, ValueMap valueMap, Field field, String propertyName) { + String parameterName = getParameterName(field); + Class fieldType = field.getType(); + if (Collection.class.isAssignableFrom(fieldType)) { + org.apache.sling.api.request.RequestParameter[] parameters = slingRequest.getRequestParameters(parameterName); + if (parameters != null) { + return getParameterValues(parameters); + } + } else { + org.apache.sling.api.request.RequestParameter parameter = slingRequest.getRequestParameter(parameterName); + if (parameter != null) { + return parameter.getString(); + } + } + return null; + } + + private List getParameterValues(org.apache.sling.api.request.RequestParameter[] parameters) { + List result = new ArrayList(); + for (org.apache.sling.api.request.RequestParameter parameter : parameters) { + result.add(parameter.getString()); + } + return result; + } + + private String getParameterName(Field field) { + final RequestParameter annotation = field.getAnnotation(RequestParameter.class); + if ((annotation != null) && StringUtils.isNotBlank(annotation.value())) { + return annotation.value(); + } + return field.getName(); + } +} diff --git a/slice-mapper/src/main/java/com/cognifide/slice/mapper/strategy/impl/AnnotatedFieldMapperStrategy.java b/slice-mapper/src/main/java/com/cognifide/slice/mapper/strategy/impl/AnnotatedFieldMapperStrategy.java index 3fab787d..a4c26352 100644 --- a/slice-mapper/src/main/java/com/cognifide/slice/mapper/strategy/impl/AnnotatedFieldMapperStrategy.java +++ b/slice-mapper/src/main/java/com/cognifide/slice/mapper/strategy/impl/AnnotatedFieldMapperStrategy.java @@ -24,11 +24,12 @@ import com.cognifide.slice.mapper.annotation.JcrProperty; import com.cognifide.slice.mapper.annotation.RequestAttribute; +import com.cognifide.slice.mapper.annotation.RequestParameter; import com.cognifide.slice.mapper.strategy.MapperStrategy; /** * AnnotatedFieldMapperStrategy defines a strategy where only fields annotated by - * {@link JcrProperty}, {@link RequestAttribute} are mapped. + * {@link JcrProperty}, {@link RequestAttribute} or {@link RequestParameter} are mapped. * */ public class AnnotatedFieldMapperStrategy implements MapperStrategy { @@ -36,7 +37,8 @@ public class AnnotatedFieldMapperStrategy implements MapperStrategy { @Override public boolean shouldFieldBeMapped(Field field) { return (field.isAnnotationPresent(JcrProperty.class) - || field.isAnnotationPresent(RequestAttribute.class)); + || field.isAnnotationPresent(RequestAttribute.class) + || field.isAnnotationPresent(RequestParameter.class)); } }