Big update. Bug fixes, code re-formatting, changing tests.

This commit is contained in:
Jon Brisbin
2012-07-26 13:31:33 -05:00
parent 6867d07295
commit 7f8abc5aa8
80 changed files with 2551 additions and 1541 deletions

View File

@@ -10,7 +10,9 @@ public interface Handler<T, V> {
/**
* Accept an argument and possibly produce a result.
*
* @param t arg
* @param t
* arg
*
* @return Some object or {@literal null} if no result.
*/
V handle(T t);

View File

@@ -0,0 +1,25 @@
package org.springframework.data.rest.core;
import java.util.ArrayList;
import java.util.List;
import org.codehaus.jackson.annotate.JsonProperty;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class Links {
private List<Link> links = new ArrayList<Link>();
public Links add(Link link) {
links.add(link);
return this;
}
@JsonProperty("_links")
public List<Link> getLinks() {
return this.links;
}
}

View File

@@ -7,10 +7,11 @@ import java.net.URI;
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class SimpleLink implements Link {
public class SimpleLink
implements Link {
private String rel;
private URI href;
private URI href;
public SimpleLink() {
}

View File

@@ -7,9 +7,14 @@ import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
* This {@link ConversionService} implementation delegates the actual conversion the ConversionService if finds in its
* internal List that claims to be able to convert a given class. It will roll through the internal <code>Stack</code>
* of <code>ConversionService</code>s until it finds one that can convert the given type.
*
* @author Jon Brisbin
*/
public class DelegatingConversionService implements ConversionService {
public class DelegatingConversionService
implements ConversionService {
private Stack<ConversionService> conversionServices = new Stack<ConversionService>();
@@ -20,21 +25,39 @@ public class DelegatingConversionService implements ConversionService {
addConversionServices(svcs);
}
/**
* Add {@link ConversionService}s to the internal list of those to delegate to.
*
* @param svcs
* The ConversionServices to delegate to (in order).
*
* @return @this
*/
public DelegatingConversionService addConversionServices(ConversionService... svcs) {
for (ConversionService svc : svcs) {
for(ConversionService svc : svcs) {
conversionServices.add(svc);
}
return this;
}
/**
* Add a {@link ConversionService} to the internal list at a specific index for controlling the priority.
*
* @param atIndex
* Where in the stack to add this ConversionService.
* @param svc
* The ConversionService to add.
*
* @return
*/
public DelegatingConversionService addConversionService(int atIndex, ConversionService svc) {
conversionServices.add(atIndex, svc);
return this;
}
@Override public boolean canConvert(Class<?> from, Class<?> to) {
for (ConversionService svc : conversionServices) {
if (svc.canConvert(from, to)) {
for(ConversionService svc : conversionServices) {
if(svc.canConvert(from, to)) {
return true;
}
}
@@ -42,8 +65,8 @@ public class DelegatingConversionService implements ConversionService {
}
@Override public boolean canConvert(TypeDescriptor from, TypeDescriptor to) {
for (ConversionService svc : conversionServices) {
if (svc.canConvert(from, to)) {
for(ConversionService svc : conversionServices) {
if(svc.canConvert(from, to)) {
return true;
}
}
@@ -51,8 +74,8 @@ public class DelegatingConversionService implements ConversionService {
}
@Override public <T> T convert(Object o, Class<T> type) {
for (ConversionService svc : conversionServices) {
if (svc.canConvert(o.getClass(), type)) {
for(ConversionService svc : conversionServices) {
if(svc.canConvert(o.getClass(), type)) {
return svc.convert(o, type);
}
}
@@ -60,8 +83,8 @@ public class DelegatingConversionService implements ConversionService {
}
@Override public Object convert(Object o, TypeDescriptor from, TypeDescriptor to) {
for (ConversionService svc : conversionServices) {
if (svc.canConvert(from, to)) {
for(ConversionService svc : conversionServices) {
if(svc.canConvert(from, to)) {
return svc.convert(o, from, to);
}
}

View File

@@ -7,7 +7,8 @@ import org.springframework.core.convert.converter.Converter;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class StringToUUIDConverter implements Converter<String, UUID> {
public class StringToUUIDConverter
implements Converter<String, UUID> {
@Override public UUID convert(String s) {
return (null != s ? UUID.fromString(s) : null);
}

View File

@@ -7,7 +7,8 @@ import org.springframework.core.convert.converter.Converter;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class UUIDToStringConverter implements Converter<UUID, String> {
public class UUIDToStringConverter
implements Converter<UUID, String> {
@Override public String convert(UUID uuid) {
return (null != uuid ? uuid.toString() : null);
}

View File

@@ -30,13 +30,14 @@ public abstract class BeanUtils {
public static ConfigurableConversionService CONVERSION_SERVICE = new DefaultConversionService();
private static final LoadingCache<Object[], Field> fields = CacheBuilder.newBuilder().build(
private static final LoadingCache<Object[], Field> fields = CacheBuilder.newBuilder().build(
new CacheLoader<Object[], Field>() {
@Override public Field load(Object[] key) throws Exception {
Class<?> clazz = (Class<?>) key[0];
String name = (String) key[1];
@Override public Field load(Object[] key)
throws Exception {
Class<?> clazz = (Class<?>)key[0];
String name = (String)key[1];
Field f = ReflectionUtils.findField(clazz, name);
if (null != f) {
if(null != f) {
ReflectionUtils.makeAccessible(f);
return f;
} else {
@@ -47,14 +48,15 @@ public abstract class BeanUtils {
);
private static final LoadingCache<Object[], Method> methods = CacheBuilder.newBuilder().build(
new CacheLoader<Object[], Method>() {
@Override public Method load(Object[] key) throws Exception {
Class<?> clazz = (Class<?>) key[0];
String name = (String) key[1];
Integer paramCnt = key.length == 3 ? (Integer) key[2] : 0;
@Override public Method load(Object[] key)
throws Exception {
Class<?> clazz = (Class<?>)key[0];
String name = (String)key[1];
Integer paramCnt = key.length == 3 ? (Integer)key[2] : 0;
for (Method m : clazz.getDeclaredMethods()) {
if (m.getName().equals(name)) {
if (m.getParameterTypes().length == paramCnt) {
for(Method m : clazz.getDeclaredMethods()) {
if(m.getName().equals(name)) {
if(m.getParameterTypes().length == paramCnt) {
ReflectionUtils.makeAccessible(m);
return m;
}
@@ -67,28 +69,28 @@ public abstract class BeanUtils {
);
public static boolean hasProperty(String property, Object... objs) {
for (Object obj : objs) {
if (obj instanceof Map) {
return ((Map) obj).containsKey(property);
for(Object obj : objs) {
if(obj instanceof Map) {
return ((Map)obj).containsKey(property);
}
Class<?> type = obj.getClass();
try {
if (FluentBeanUtils.isFluentBean(type)) {
if(FluentBeanUtils.isFluentBean(type)) {
return null != methods.get(new Object[]{type, property});
} else {
if (null == methods.get(new Object[]{type, "get" + StringUtils.capitalize(property)})) {
if(null == methods.get(new Object[]{type, "get" + StringUtils.capitalize(property)})) {
return null != fields.get(new Object[]{type, property});
} else {
return true;
}
}
} catch (UncheckedExecutionException e) {
if (e.getCause().getClass() == IllegalArgumentException.class) {
} catch(UncheckedExecutionException e) {
if(e.getCause().getClass() == IllegalArgumentException.class) {
return false;
} else {
throw new IllegalStateException(e);
}
} catch (ExecutionException e) {
} catch(ExecutionException e) {
throw new IllegalStateException(e);
}
}
@@ -97,9 +99,9 @@ public abstract class BeanUtils {
@SuppressWarnings({"unchecked"})
public static <T> T findFirst(Class<T> clazz, List<?> stack) {
for (Object o : stack) {
if (ClassUtils.isAssignable(clazz, o.getClass())) {
return (T) o;
for(Object o : stack) {
if(ClassUtils.isAssignable(clazz, o.getClass())) {
return (T)o;
}
}
return null;
@@ -107,44 +109,44 @@ public abstract class BeanUtils {
@SuppressWarnings({"unchecked"})
public static Object findFirst(Object o, Object... objs) {
for (Object obj : objs) {
if (o == obj || null != o && o.equals(obj)) {
for(Object obj : objs) {
if(o == obj || null != o && o.equals(obj)) {
return obj;
} else if (obj instanceof List) {
return Collections.binarySearch((List) obj, o);
} else if (obj instanceof Object[]) {
return Arrays.binarySearch((Object[]) obj, o);
} else if(obj instanceof List) {
return Collections.binarySearch((List)obj, o);
} else if(obj instanceof Object[]) {
return Arrays.binarySearch((Object[])obj, o);
}
}
return null;
}
public static Object findFirst(String property, Object... objs) {
for (Object obj : objs) {
if (obj instanceof Map) {
return ((Map) obj).get(property);
for(Object obj : objs) {
if(obj instanceof Map) {
return ((Map)obj).get(property);
}
Class<?> type = obj.getClass();
try {
Field f = fields.get(new Object[]{type, property});
if (FluentBeanUtils.isFluentBean(type)) {
if(FluentBeanUtils.isFluentBean(type)) {
return FluentBeanUtils.get(property, obj);
} else {
Method getter = methods.get(new Object[]{type, "get" + StringUtils.capitalize(property)});
try {
if (null != getter) {
if(null != getter) {
return getter.invoke(obj);
} else {
return f.get(obj);
}
} catch (IllegalAccessException e) {
} catch(IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
} catch(InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
} catch (IllegalArgumentException e) {
} catch (ExecutionException e) {
} catch(IllegalArgumentException e) {
} catch(ExecutionException e) {
throw new IllegalArgumentException(e);
}
}
@@ -157,8 +159,8 @@ public abstract class BeanUtils {
}
public static boolean containsType(Class<?> type, Object[] objs) {
for (Object obj : objs) {
if (null != obj && ClassUtils.isAssignable(obj.getClass(), type)) {
for(Object obj : objs) {
if(null != obj && ClassUtils.isAssignable(obj.getClass(), type)) {
return true;
}
}
@@ -172,7 +174,7 @@ public abstract class BeanUtils {
@SuppressWarnings({"unchecked"})
public static <T> T invoke(String methodName, Object target, Class<T> returnType, Object... args) {
if (null == target) {
if(null == target) {
return null;
}
@@ -181,11 +183,11 @@ public abstract class BeanUtils {
Method m = methods.get(new Object[]{type, methodName, args.length});
List<Object> newArgs = new ArrayList<Object>(args.length);
Class<?>[] paramTypes = m.getParameterTypes();
for (int i = 0; i < args.length; i++) {
for(int i = 0; i < args.length; i++) {
Object o = args[i];
Class<?> oType = o.getClass();
Class<?> pType = paramTypes[i];
if (!ClassUtils.isAssignable(oType, pType)) {
if(!ClassUtils.isAssignable(oType, pType)) {
newArgs.add(CONVERSION_SERVICE.convert(o, pType));
} else {
newArgs.add(o);
@@ -193,15 +195,15 @@ public abstract class BeanUtils {
}
Object rtnVal = m.invoke(target, newArgs.toArray());
if ((returnType != Void.TYPE || returnType != Object.class)
if((returnType != Void.TYPE || returnType != Object.class)
&& null != rtnVal
&& !ClassUtils.isAssignable(returnType, rtnVal.getClass())) {
return CONVERSION_SERVICE.convert(rtnVal, returnType);
} else {
return (T) rtnVal;
return (T)rtnVal;
}
} catch (IllegalArgumentException e) {
} catch (Exception e) {
} catch(IllegalArgumentException e) {
} catch(Exception e) {
throw new IllegalStateException(e);
}

View File

@@ -18,9 +18,10 @@ import org.springframework.util.ClassUtils;
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class FluentBeanDeserializer extends StdDeserializer {
public class FluentBeanDeserializer
extends StdDeserializer {
private ConversionService conversionService;
private ConversionService conversionService;
private FluentBeanUtils.Metadata beanMeta;
@SuppressWarnings({"unchecked"})
@@ -29,7 +30,7 @@ public class FluentBeanDeserializer extends StdDeserializer {
this.conversionService = conversionService;
this.beanMeta = FluentBeanUtils.metadata(valueClass);
if (!FluentBeanUtils.isFluentBean(valueClass)) {
if(!FluentBeanUtils.isFluentBean(valueClass)) {
throw new IllegalArgumentException("Class of type " + valueClass + " is not a FluentBean");
}
}
@@ -39,46 +40,46 @@ public class FluentBeanDeserializer extends StdDeserializer {
DeserializationContext ctxt)
throws IOException,
JsonProcessingException {
if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
if(jp.getCurrentToken() != JsonToken.START_OBJECT) {
throw ctxt.mappingException(_valueClass);
}
Object bean;
try {
bean = _valueClass.newInstance();
} catch (InstantiationException e) {
} catch(InstantiationException e) {
throw new IllegalStateException(e);
} catch (IllegalAccessException e) {
} catch(IllegalAccessException e) {
throw new IllegalStateException(e);
}
while (jp.nextToken() != JsonToken.END_OBJECT) {
while(jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
Method setter = beanMeta.setters().get(name);
Object obj;
if (null != setter) {
if(null != setter) {
Class<?> targetType = setter.getParameterTypes()[0];
if (ClassUtils.isAssignable(targetType, Long.class)) {
if(ClassUtils.isAssignable(targetType, Long.class)) {
obj = jp.nextLongValue(-1);
} else if (ClassUtils.isAssignable(targetType, Integer.class)) {
} else if(ClassUtils.isAssignable(targetType, Integer.class)) {
obj = jp.nextIntValue(-1);
} else if (ClassUtils.isAssignable(targetType, Boolean.class)) {
} else if(ClassUtils.isAssignable(targetType, Boolean.class)) {
obj = jp.nextBooleanValue();
} else {
obj = jp.nextTextValue();
}
if (null != obj) {
if (!ClassUtils.isAssignable(obj.getClass(), targetType)) {
if(null != obj) {
if(!ClassUtils.isAssignable(obj.getClass(), targetType)) {
obj = conversionService.convert(obj, targetType);
}
try {
setter.invoke(bean, obj);
} catch (IllegalAccessException e) {
} catch(IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
} catch(InvocationTargetException e) {
throw new IllegalStateException(e);
}
}

View File

@@ -16,60 +16,62 @@ import org.springframework.util.ClassUtils;
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class FluentBeanSerializer extends SerializerBase<Object> {
public class FluentBeanSerializer
extends SerializerBase<Object> {
@SuppressWarnings({"unchecked", "rawtypes"})
public FluentBeanSerializer( final Class t ) {
super( t );
public FluentBeanSerializer(final Class t) {
super(t);
if ( !FluentBeanUtils.isFluentBean( t ) ) {
throw new IllegalArgumentException( "Class of type " + t + " is not a FluentBean" );
if(!FluentBeanUtils.isFluentBean(t)) {
throw new IllegalArgumentException("Class of type " + t + " is not a FluentBean");
}
}
@SuppressWarnings({"unchecked"})
@Override
public void serialize( final Object value,
final JsonGenerator jgen,
final SerializerProvider provider )
public void serialize(final Object value,
final JsonGenerator jgen,
final SerializerProvider provider)
throws IOException,
JsonGenerationException {
if ( null == value ) {
provider.defaultSerializeNull( jgen );
if(null == value) {
provider.defaultSerializeNull(jgen);
} else {
Class<?> type = value.getClass();
if ( ClassUtils.isAssignable( type, Collection.class ) ) {
if(ClassUtils.isAssignable(type, Collection.class)) {
jgen.writeStartArray();
for ( Object o : (Collection) value ) {
write( o, jgen, provider );
for(Object o : (Collection)value) {
write(o, jgen, provider);
}
jgen.writeEndArray();
} else if ( ClassUtils.isAssignable( type, Map.class ) ) {
} else if(ClassUtils.isAssignable(type, Map.class)) {
jgen.writeStartObject();
for ( Map.Entry<String, Object> entry : ((Map<String, Object>) value).entrySet() ) {
jgen.writeFieldName( entry.getKey() );
write( entry.getValue(), jgen, provider );
for(Map.Entry<String, Object> entry : ((Map<String, Object>)value).entrySet()) {
jgen.writeFieldName(entry.getKey());
write(entry.getValue(), jgen, provider);
}
jgen.writeEndObject();
} else {
write( value, jgen, provider );
write(value, jgen, provider);
}
}
}
private void write( final Object value,
final JsonGenerator jgen,
final SerializerProvider provider ) throws IOException {
private void write(final Object value,
final JsonGenerator jgen,
final SerializerProvider provider)
throws IOException {
Class<?> type = value.getClass();
if ( ClassUtils.isAssignable( type, _handledType ) ) {
if(ClassUtils.isAssignable(type, _handledType)) {
jgen.writeStartObject();
for ( String fname : FluentBeanUtils.metadata( type ).fieldNames() ) {
jgen.writeFieldName( fname );
write( FluentBeanUtils.get( fname, value ), jgen, provider );
for(String fname : FluentBeanUtils.metadata(type).fieldNames()) {
jgen.writeFieldName(fname);
write(FluentBeanUtils.get(fname, value), jgen, provider);
}
jgen.writeEndObject();
} else {
jgen.writeObject( value );
jgen.writeObject(value);
}
}

View File

@@ -22,24 +22,27 @@ import org.springframework.util.ReflectionUtils;
*/
public abstract class FluentBeanUtils {
private static final Logger log = LoggerFactory.getLogger(FluentBeanUtils.class);
private static final Logger log = LoggerFactory.getLogger(FluentBeanUtils.class);
private static final LoadingCache<Class<?>, Metadata> metadata = CacheBuilder.newBuilder().build(
new CacheLoader<Class<?>, Metadata>() {
@Override public Metadata load(Class<?> type) throws Exception {
@Override public Metadata load(Class<?> type)
throws Exception {
final Metadata meta = new Metadata();
ReflectionUtils.doWithFields(
type,
new ReflectionUtils.FieldCallback() {
@Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
@Override public void doWith(Field field)
throws IllegalArgumentException, IllegalAccessException {
final String fname = field.getName();
if (!fname.startsWith("_")) {
if(!fname.startsWith("_")) {
ReflectionUtils.doWithMethods(field.getDeclaringClass(), new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
if (method.getName().equals(fname)) {
if (method.getParameterTypes().length == 0) {
public void doWith(Method method)
throws IllegalArgumentException, IllegalAccessException {
if(method.getName().equals(fname)) {
if(method.getParameterTypes().length == 0) {
meta.getters.put(fname, method);
} else if (method.getParameterTypes().length == 1) {
} else if(method.getParameterTypes().length == 1) {
meta.setters.put(fname, method);
}
meta.fieldNames.add(fname);
@@ -58,13 +61,15 @@ public abstract class FluentBeanUtils {
/**
* Interrogate a bean and collect {@link Metadata} on it.
*
* @param targetType The type to interrogate.
* @param targetType
* The type to interrogate.
*
* @return {@link Metadata} for the fluent bean.
*/
public static Metadata metadata(Class<?> targetType) {
try {
return metadata.get(targetType);
} catch (ExecutionException e) {
} catch(ExecutionException e) {
throw new IllegalStateException(e);
}
}
@@ -72,27 +77,31 @@ public abstract class FluentBeanUtils {
/**
* Set the property of a fluent bean.
*
* @param property Name of the property to set.
* @param value Value of the property.
* @param bean Bean on which to set this property.
* @param property
* Name of the property to set.
* @param value
* Value of the property.
* @param bean
* Bean on which to set this property.
*
* @return Usually {@literal null} but will return whatever the "setter" returns, which could be {@this} or something
* else.
*/
public static Object set(String property, Object value, Object bean) {
if (null == bean) {
if(null == bean) {
return null;
}
Class<?> type = bean.getClass();
try {
Method setter = metadata.get(type).setters.get(property);
if (null != setter) {
if(null != setter) {
return setter.invoke(bean, value);
} else {
return null;
}
} catch (Throwable t) {
if (log.isDebugEnabled()) {
} catch(Throwable t) {
if(log.isDebugEnabled()) {
log.debug(t.getMessage(), t);
}
return null;
@@ -102,25 +111,28 @@ public abstract class FluentBeanUtils {
/**
* Get the value of a property.
*
* @param property Name of the property.
* @param bean Bean of which to get the property.
* @param property
* Name of the property.
* @param bean
* Bean of which to get the property.
*
* @return Value of the property. Could be {@literal null}
*/
public static Object get(String property, Object bean) {
if (null == bean) {
if(null == bean) {
return null;
}
Class<?> type = bean.getClass();
try {
Method getter = metadata.get(type).getters.get(property);
if (null != getter) {
if(null != getter) {
return getter.invoke(bean);
} else {
return null;
}
} catch (Throwable t) {
if (log.isDebugEnabled()) {
} catch(Throwable t) {
if(log.isDebugEnabled()) {
log.debug(t.getMessage(), t);
}
return null;
@@ -132,21 +144,23 @@ public abstract class FluentBeanUtils {
* to a field of the same name. A "getter" is that method which is named the same as the field and has 0 parameters.
* The "setter" is that method which is named the same as the field and has a single argument.
*
* @param type The class to inspect.
* @param type
* The class to inspect.
*
* @return {@literal true} if this looks like a fluent bean, {@literal false} otherwise.
*/
public static boolean isFluentBean(Class<?> type) {
try {
return metadata.get(type).getters.size() > 0;
} catch (ExecutionException e) {
} catch(ExecutionException e) {
throw new IllegalStateException(e);
}
}
public static class Metadata {
List<String> fieldNames = new ArrayList<String>();
Map<String, Method> getters = new HashMap<String, Method>();
Map<String, Method> setters = new HashMap<String, Method>();
List<String> fieldNames = new ArrayList<String>();
Map<String, Method> getters = new HashMap<String, Method>();
Map<String, Method> setters = new HashMap<String, Method>();
public List<String> fieldNames() {
return fieldNames;

View File

@@ -24,8 +24,11 @@ public abstract class UriUtils {
* http://localhost:8080/data/person}, this method would report the baseUri being a valid base of the given URI.
* </p>
*
* @param baseUri {@link URI} to check.
* @param uri {@link URI} against which to compare the base.
* @param baseUri
* {@link URI} to check.
* @param uri
* {@link URI} against which to compare the base.
*
* @return {@literal true} if the baseUri is valid against the given {@link URI}, {@literal false} otherwise.
*/
public static boolean validBaseUri(URI baseUri, URI uri) {
@@ -41,16 +44,21 @@ public abstract class UriUtils {
* second time passing a relative {@link URI} of "1".
* </p>
*
* @param baseUri base {@link URI}
* @param uri {@link URI} to explode and iteratre over.
* @param handler {@link Handler} to call for each segment of the URI's path.
* @param <V> Return type of the handler.
* @param baseUri
* base {@link URI}
* @param uri
* {@link URI} to explode and iteratre over.
* @param handler
* {@link Handler} to call for each segment of the URI's path.
* @param <V>
* Return type of the handler.
*
* @return Handler return value, or possibly {@literal null}.
*/
public static <V> V foreach(URI baseUri, URI uri, Handler<URI, V> handler) {
List<URI> uris = explode(baseUri, uri);
V v = null;
for (URI u : uris) {
for(URI u : uris) {
v = handler.handle(u);
}
return v;
@@ -63,16 +71,19 @@ public abstract class UriUtils {
* in
* a {@link Stack} of relative {@link URI}s of size 2--one for "person" and one for "1".</p>
*
* @param baseUri base {@link URI}
* @param uri {@link URI} to explode
* @param baseUri
* base {@link URI}
* @param uri
* {@link URI} to explode
*
* @return {@link Stack} of relative {@link URI}s.
*/
public static Stack<URI> explode(URI baseUri, URI uri) {
Stack<URI> uris = new Stack<URI>();
if (StringUtils.hasText(uri.getPath())) {
if(StringUtils.hasText(uri.getPath())) {
URI relativeUri = baseUri.relativize(uri);
if (StringUtils.hasText(relativeUri.getPath())) {
for (String part : relativeUri.getPath().split("/")) {
if(StringUtils.hasText(relativeUri.getPath())) {
for(String part : relativeUri.getPath().split("/")) {
uris.add(URI.create(part + (StringUtils.hasText(uri.getQuery()) ? "?" + uri.getQuery() : "")));
}
}
@@ -86,38 +97,41 @@ public abstract class UriUtils {
* <p>e.g. merging base URI {@literal http://localhost:8080/data} and relative uri {@literal person/1?name=John+Doe}
* would result in an absolute URI of {@literal http://localhost:8080/data/person/1?name=John+Doe}</p>
*
* @param baseUri base {@link URI}
* @param uris {@link URI}s to merge
* @param baseUri
* base {@link URI}
* @param uris
* {@link URI}s to merge
*
* @return {@link URI} that is the combination of all the given (possibly relative, possibly absolute) URIs.
*/
public static URI merge(URI baseUri, URI... uris) {
StringBuilder query = new StringBuilder();
UriComponentsBuilder ub = UriComponentsBuilder.fromUri(baseUri);
for (URI uri : uris) {
for(URI uri : uris) {
String s = uri.getScheme();
if (null != s) {
if(null != s) {
ub.scheme(s);
}
s = uri.getUserInfo();
if (null != s) {
if(null != s) {
ub.userInfo(s);
}
s = uri.getHost();
if (null != s) {
if(null != s) {
ub.host(s);
}
int i = uri.getPort();
if (i > 0) {
if(i > 0) {
ub.port(i);
}
s = uri.getPath();
if (null != s) {
if (!uri.isAbsolute() && StringUtils.hasText(s)) {
if(null != s) {
if(!uri.isAbsolute() && StringUtils.hasText(s)) {
ub.pathSegment(s);
} else {
ub.path(s);
@@ -125,20 +139,20 @@ public abstract class UriUtils {
}
s = uri.getQuery();
if (null != s) {
if (query.length() > 0) {
if(null != s) {
if(query.length() > 0) {
query.append("&");
}
query.append(s);
}
s = uri.getFragment();
if (null != s) {
if(null != s) {
ub.fragment(s);
}
}
if (query.length() > 0) {
if(query.length() > 0) {
ub.query(query.toString());
}
@@ -149,14 +163,15 @@ public abstract class UriUtils {
* Just the path portion of the {@link URI}, but with any trailing slash "/" removed.
*
* @param uri
*
* @return
*/
public static String path(URI uri) {
if (null == uri) {
if(null == uri) {
return null;
}
String s = uri.getPath();
if (s.endsWith("/")) {
if(s.endsWith("/")) {
return s.substring(0, s.length() - 1);
} else {
return s;
@@ -166,8 +181,11 @@ public abstract class UriUtils {
/**
* The very last segment of the {@link URI}.
*
* @param baseUri base {@link URI}
* @param uri {@link URI} to explode
* @param baseUri
* base {@link URI}
* @param uri
* {@link URI} to explode
*
* @return Relative {@link URI} that is the last segment of the path for the given URI.
*/
public static URI tail(URI baseUri, URI uri) {