
com.damnhandy.uri.template.DefaultVarExploder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.liferay.search.experiences.service
Show all versions of com.liferay.search.experiences.service
Liferay Search Experiences Service
The newest version!
/*
* Copyright 2012, Ryan J. McDonough
*
* 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.
*/
package com.damnhandy.uri.template;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
/**
*
* The {@link DefaultVarExploder} is a {@link VarExploder} implementation that takes in a Java object and
* extracts the properties for use in a URI Template. Given the following URI expression:
*
*
* /mapper{?address*}
*
*
* And this Java object for an address:
*
*
* Address address = new Address();
* address.setState("CA");
* address.setCity("Newport Beach");
* String result = UriTemplate.fromTemplate("/mapper{?address*}").set("address", address).expand();
*
*
* The expanded URI will be:
*
*
* /mapper?city=Newport%20Beach&state=CA
*
*
*
* The {@link DefaultVarExploder} breaks down the object properties as follows:
*
* - All properties that contain a non-null return value will be included
* - Getters or fields annotated with {@link UriTransient} will NOT included in the list
* - By default, the property name is used as the label in the URI. This can be overridden by
* placing the {@link VarName} annotation on the field or getter method and specifying a name.
* - Field level annotation take priority of getter annotations
*
*
* @author Ryan J. McDonough
* @version $Revision: 1.1 $
* @see VarName
* @see UriTransient
* @see VarExploder
* @since 1.0
*/
public class DefaultVarExploder implements VarExploder
{
/**
*
*/
private static final String GET_PREFIX = "get";
/**
*
*/
private static final String IS_PREIX = "is";
/**
* The original object.
*/
private Object source;
/**
* The objects properties that have been extracted to a {@link Map}
*/
private Map pairs = new TreeMap();
/**
* @param source the Object to explode
*/
public DefaultVarExploder(Object source) throws VarExploderException
{
this.setSource(source);
}
/**
* @return the name value pairs of the input
*/
@Override
public Map getNameValuePairs()
{
return pairs;
}
/**
*
* @param source
* @throws VarExploderException
*/
void setSource(Object source) throws VarExploderException
{
this.source = source;
this.initValues();
}
/**
* Initializes the values from the object properties and constructs a
* map from those values.
*
* @throws VarExploderException
*/
private void initValues() throws VarExploderException
{
Class> c = source.getClass();
if (c.isAnnotation() || c.isArray() || c.isEnum() || c.isPrimitive())
{
throw new IllegalArgumentException("The value must an object");
}
if(source instanceof Map )
{
this.pairs = (Map) source;
return;
}
Method[] methods = c.getMethods();
for (Method method : methods)
{
inspectGetters(method);
}
scanFields(c);
}
/**
* A lite version of the introspection logic performed by the BeanInfo introspector.
* @param method
*/
private void inspectGetters(Method method)
{
String methodName = method.getName();
int prefixLength = 0;
if (methodName.startsWith(GET_PREFIX)) {
prefixLength = GET_PREFIX.length();
}
if (methodName.startsWith(IS_PREIX)) {
prefixLength = IS_PREIX.length();
}
if(prefixLength == 0)
{
return;
}
String name = decapitalize(methodName.substring(prefixLength));
if(!isValidProperty(name))
{
return;
}
// Check that the return type is not null or void
Class propertyType = method.getReturnType();
if (propertyType == null || propertyType == void.class)
{
return;
}
// isXXX return boolean
if (prefixLength == 2)
{
if (!(propertyType == boolean.class))
{
return;
}
}
// validate parameter types
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length > 1 ||
(paramTypes.length == 1 && paramTypes[0] != int.class))
{
return;
}
if (!method.isAnnotationPresent(UriTransient.class) && !"class".equals(name))
{
Object value = getValue(method);
if (method.isAnnotationPresent(VarName.class))
{
name = method.getAnnotation(VarName.class).value();
}
if (value != null)
{
pairs.put(name, value);
}
}
}
private static boolean isValidProperty(String propertyName) {
return (propertyName != null) && (propertyName.length() != 0);
}
static String decapitalize(String name)
{
if (name == null)
return null;
// The rule for decapitalize is that:
// If the first letter of the string is Upper Case, make it lower case
// UNLESS the second letter of the string is also Upper Case, in which case no
// changes are made.
if (name.length() == 0 || (name.length() > 1 && Character.isUpperCase(name.charAt(1)))) {
return name;
}
char[] chars = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
/**
* Scans the fields on the class or super classes to look for
* field-level annotations.
*
* @param c
*/
private void scanFields(Class> c)
{
if (!c.isInterface())
{
Field[] fields = c.getDeclaredFields();
for (Field field : fields)
{
String fieldName = field.getName();
if (pairs.containsKey(fieldName))
{
if (field.isAnnotationPresent(UriTransient.class))
{
pairs.remove(fieldName);
}
else if (field.isAnnotationPresent(VarName.class))
{
String name = field.getAnnotation(VarName.class).value();
pairs.put(name, pairs.get(fieldName));
pairs.remove(fieldName);
}
}
}
}
/*
* We still need to scan the fields of the super class if its
* not Object to check for annotations. There might be a better
* way to do this.
*/
if (!c.getSuperclass().equals(Object.class))
{
scanFields(c.getSuperclass());
}
}
/**
* Return the value of the property.
*
* @param method
* @return
* @throws VarExploderException
*/
private Object getValue(Method method) throws VarExploderException
{
try
{
if (method == null)
{
return null;
}
return method.invoke(source);
}
catch (IllegalArgumentException e)
{
throw new VarExploderException(e);
}
catch (IllegalAccessException e)
{
throw new VarExploderException(e);
}
catch (InvocationTargetException e)
{
throw new VarExploderException(e);
}
}
@Override
public Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy