Re-org submodules, add debug compiler options

This commit is contained in:
Jon Brisbin
2012-04-11 15:44:20 -05:00
parent 492519f150
commit e49014542c
46 changed files with 6 additions and 14 deletions

View File

@@ -0,0 +1,8 @@
package org.springframework.data.rest.core;
/**
* @author Jon Brisbin <jon@jbrisbin.com>
*/
public interface Handler<T,V> {
V handle(T t);
}

View File

@@ -0,0 +1,14 @@
package org.springframework.data.rest.core;
import java.net.URI;
/**
* @author Jon Brisbin <jon@jbrisbin.com>
*/
public interface Link {
String rel();
URI href();
}

View File

@@ -0,0 +1,36 @@
package org.springframework.data.rest.core;
import java.net.URI;
/**
* @author Jon Brisbin <jon@jbrisbin.com>
*/
public class SimpleLink implements Link {
private String rel;
private URI href;
public SimpleLink() {
}
public SimpleLink(String rel, URI href) {
this.rel = rel;
this.href = href;
}
@Override public String rel() {
return rel;
}
@Override public URI href() {
return href;
}
@Override public String toString() {
return "SimpleLink{" +
"rel='" + rel + '\'' +
", href=" + href +
'}';
}
}

View File

@@ -0,0 +1,211 @@
package org.springframework.data.rest.core.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* @author Jon Brisbin <jon@jbrisbin.com>
*/
public abstract class BeanUtils {
private BeanUtils() {
}
public static ConfigurableConversionService CONVERSION_SERVICE = new DefaultConversionService();
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];
Field f = ReflectionUtils.findField(clazz, name);
if (null != f) {
ReflectionUtils.makeAccessible(f);
return f;
} else {
throw new IllegalArgumentException("Field " + clazz.getName() + "." + name + " not found");
}
}
}
);
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;
for (Method m : clazz.getDeclaredMethods()) {
if (m.getName().equals(name)) {
if (m.getParameterTypes().length == paramCnt) {
ReflectionUtils.makeAccessible(m);
return m;
}
}
}
throw new IllegalArgumentException("Method " + clazz.getName() + "." + name + " not found");
}
}
);
public static boolean hasProperty(String property, Object... objs) {
for (Object obj : objs) {
if (obj instanceof Map) {
return ((Map) obj).containsKey(property);
}
Class<?> type = obj.getClass();
try {
if (FluentBeanUtils.isFluentBean(type)) {
return null != methods.get(new Object[]{type, property});
} else {
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) {
return false;
} else {
throw new IllegalStateException(e);
}
} catch (ExecutionException e) {
throw new IllegalStateException(e);
}
}
return false;
}
@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;
}
}
return null;
}
@SuppressWarnings({"unchecked"})
public static Object findFirst(Object o, Object... objs) {
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);
}
}
return null;
}
public static Object findFirst(String property, Object... objs) {
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)) {
return FluentBeanUtils.get(property, obj);
} else {
Method getter = methods.get(new Object[]{type, "get" + StringUtils.capitalize(property)});
try {
if (null != getter) {
return getter.invoke(obj);
} else {
return f.get(obj);
}
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
} catch (IllegalArgumentException e) {
} catch (ExecutionException e) {
throw new IllegalArgumentException(e);
}
}
return null;
}
public static boolean containsType(Class<?> type, List<Object> objs) {
return containsType(type, objs.toArray());
}
public static boolean containsType(Class<?> type, Object[] objs) {
for (Object obj : objs) {
if (null != obj && ClassUtils.isAssignable(obj.getClass(), type)) {
return true;
}
}
return false;
}
@SuppressWarnings({"unchecked"})
public static Object invoke(String methodName, Object target, Object... args) {
return invoke(methodName, target, Object.class, args);
}
@SuppressWarnings({"unchecked"})
public static <T> T invoke(String methodName, Object target, Class<T> returnType, Object... args) {
if (null == target) {
return null;
}
Class<?> type = target.getClass();
try {
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++) {
Object o = args[i];
Class<?> oType = o.getClass();
Class<?> pType = paramTypes[i];
if (!ClassUtils.isAssignable(oType, pType)) {
newArgs.add(CONVERSION_SERVICE.convert(o, pType));
} else {
newArgs.add(o);
}
}
Object rtnVal = m.invoke(target, newArgs.toArray());
if ((returnType != Void.TYPE || returnType != Object.class)
&& null != rtnVal
&& !ClassUtils.isAssignable(returnType, rtnVal.getClass())) {
return CONVERSION_SERVICE.convert(rtnVal, returnType);
} else {
return (T) rtnVal;
}
} catch (IllegalArgumentException e) {
} catch (Exception e) {
throw new IllegalStateException(e);
}
return null;
}
}

View File

@@ -0,0 +1,89 @@
package org.springframework.data.rest.core.util;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.deser.std.StdDeserializer;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.ClassUtils;
/**
* @author Jon Brisbin <jon@jbrisbin.com>
*/
public class FluentBeanDeserializer extends StdDeserializer {
private ConversionService conversionService;
private FluentBeanUtils.Metadata beanMeta;
@SuppressWarnings({"unchecked"})
public FluentBeanDeserializer(final Class<?> valueClass, ConversionService conversionService) {
super(valueClass);
this.conversionService = conversionService;
this.beanMeta = FluentBeanUtils.metadata(valueClass);
if (!FluentBeanUtils.isFluentBean(valueClass)) {
throw new IllegalArgumentException("Class of type " + valueClass + " is not a FluentBean");
}
}
@Override
public Object deserialize(JsonParser jp,
DeserializationContext ctxt)
throws IOException,
JsonProcessingException {
if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
throw ctxt.mappingException(_valueClass);
}
Object bean;
try {
bean = _valueClass.newInstance();
} catch (InstantiationException e) {
throw new IllegalStateException(e);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
while (jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
Method setter = beanMeta.setters().get(name);
Object obj;
if (null != setter) {
Class<?> targetType = setter.getParameterTypes()[0];
if (ClassUtils.isAssignable(targetType, Long.class)) {
obj = jp.nextLongValue(-1);
} else if (ClassUtils.isAssignable(targetType, Integer.class)) {
obj = jp.nextIntValue(-1);
} else if (ClassUtils.isAssignable(targetType, Boolean.class)) {
obj = jp.nextBooleanValue();
} else {
obj = jp.nextTextValue();
}
if (null != obj) {
if (!ClassUtils.isAssignable(obj.getClass(), targetType)) {
obj = conversionService.convert(obj, targetType);
}
try {
setter.invoke(bean, obj);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
}
}
return bean;
}
}

View File

@@ -0,0 +1,75 @@
package org.springframework.data.rest.core.util;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.ser.std.SerializerBase;
import org.springframework.util.ClassUtils;
/**
* @author Jon Brisbin <jon@jbrisbin.com>
*/
public class FluentBeanSerializer extends SerializerBase {
@SuppressWarnings({"unchecked"})
public FluentBeanSerializer(final Class<?> t) {
super(t);
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)
throws IOException,
JsonGenerationException {
if (null == value) {
provider.defaultSerializeNull(jgen);
} else {
Class<?> type = value.getClass();
if (ClassUtils.isAssignable(type, Collection.class)) {
jgen.writeStartArray();
for (Object o : (Collection) value) {
write(o, jgen, provider);
}
jgen.writeEndArray();
} 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);
}
jgen.writeEndObject();
} else {
write(value, jgen, provider);
}
}
}
private void write(final Object value,
final JsonGenerator jgen,
final SerializerProvider provider) throws IOException {
Class<?> type = value.getClass();
if (ClassUtils.isAssignable(type, _handledType)) {
jgen.writeStartObject();
for (String fname : FluentBeanUtils.metadata(type).fieldNames()) {
jgen.writeFieldName(fname);
write(FluentBeanUtils.get(fname, value), jgen, provider);
}
jgen.writeEndObject();
} else {
jgen.writeObject(value);
}
}
}

View File

@@ -0,0 +1,132 @@
package org.springframework.data.rest.core.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
/**
* @author Jon Brisbin <jon@jbrisbin.com>
*/
public abstract class FluentBeanUtils {
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 {
final Metadata meta = new Metadata();
ReflectionUtils.doWithFields(
type,
new ReflectionUtils.FieldCallback() {
@Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
final String fname = field.getName();
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) {
meta.getters.put(fname, method);
} else if (method.getParameterTypes().length == 1) {
meta.setters.put(fname, method);
}
meta.fieldNames.add(fname);
}
}
});
}
}
}
);
return meta;
}
}
);
public static Metadata metadata(Class<?> targetType) {
try {
return metadata.get(targetType);
} catch (ExecutionException e) {
throw new IllegalStateException(e);
}
}
public static Object set(String property, Object value, Object bean) {
if (null == bean) {
return null;
}
Class<?> type = bean.getClass();
try {
Method setter = metadata.get(type).setters.get(property);
if (null != setter) {
return setter.invoke(bean, value);
} else {
return null;
}
} catch (Throwable t) {
if (log.isDebugEnabled()) {
log.debug(t.getMessage(), t);
}
return null;
}
}
public static Object get(String property, Object bean) {
if (null == bean) {
return null;
}
Class<?> type = bean.getClass();
try {
Method getter = metadata.get(type).getters.get(property);
if (null != getter) {
return getter.invoke(bean);
} else {
return null;
}
} catch (Throwable t) {
if (log.isDebugEnabled()) {
log.debug(t.getMessage(), t);
}
return null;
}
}
public static boolean isFluentBean(Class<?> type) {
try {
return metadata.get(type).getters.size() > 0;
} 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>();
public List<String> fieldNames() {
return fieldNames;
}
public Map<String, Method> getters() {
return getters;
}
public Map<String, Method> setters() {
return setters;
}
}
}

View File

@@ -0,0 +1,118 @@
package org.springframework.data.rest.core.util;
import java.net.URI;
import java.util.List;
import java.util.Stack;
import org.springframework.data.rest.core.Handler;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
/**
* @author Jon Brisbin <jon@jbrisbin.com>
*/
public abstract class UriUtils {
private UriUtils() {
}
public static boolean validBaseUri(URI baseUri, URI uri) {
String path = UriUtils.path(baseUri.relativize(uri));
return !StringUtils.hasText(path) || path.charAt(0) != '/';
}
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) {
v = handler.handle(u);
}
return v;
}
public static Stack<URI> explode(URI baseUri, URI uri) {
Stack<URI> uris = new Stack<URI>();
if (StringUtils.hasText(uri.getPath())) {
URI relativeUri = baseUri.relativize(uri);
if (StringUtils.hasText(relativeUri.getPath())) {
for (String part : relativeUri.getPath().split("/")) {
uris.add(URI.create(part + (StringUtils.hasText(uri.getQuery()) ? "?" + uri.getQuery() : "")));
}
}
}
return uris;
}
public static URI merge(URI baseUri, URI... uris) {
StringBuilder query = new StringBuilder();
UriComponentsBuilder ub = UriComponentsBuilder.fromUri(baseUri);
for (URI uri : uris) {
String s = uri.getScheme();
if (null != s) {
ub.scheme(s);
}
s = uri.getUserInfo();
if (null != s) {
ub.userInfo(s);
}
s = uri.getHost();
if (null != s) {
ub.host(s);
}
int i = uri.getPort();
if (i > 0) {
ub.port(i);
}
s = uri.getPath();
if (null != s) {
if (!uri.isAbsolute() && StringUtils.hasText(s)) {
ub.pathSegment(s);
} else {
ub.path(s);
}
}
s = uri.getQuery();
if (null != s) {
if (query.length() > 0) {
query.append("&");
}
query.append(s);
}
s = uri.getFragment();
if (null != s) {
ub.fragment(s);
}
}
if (query.length() > 0) {
ub.query(query.toString());
}
return ub.build().toUri();
}
public static String path(URI uri) {
if (null == uri) {
return null;
}
String s = uri.getPath();
if (s.endsWith("/")) {
return s.substring(0, s.length() - 1);
} else {
return s;
}
}
public static URI tail(URI baseUri, URI uri) {
Stack<URI> uris = explode(baseUri, uri);
return uris.size() > 0 ? uris.get(Math.max(uris.size() - 1, 0)) : null;
}
}

View File

@@ -0,0 +1,48 @@
package org.springframework.data.rest.core.spec
import org.springframework.data.rest.core.util.UriUtils
import spock.lang.Specification
/**
* @author Jon Brisbin <jon@jbrisbin.com>
*/
class UriUtilsSpec extends Specification {
def "merges URIs correctly"() {
given:
// (absolute) URI of the base resource
def baseUri = new URI("http://localhost:8080/baseUrl")
// (relative) URI of the top-level Resource
def uri2 = new URI("resource")
// (relative) URI of the second-level Resource
def uri3 = new URI("1")
// (fragment) URI of the bottom-level Resource
def uri4 = new URI("count")
when:
def uri5 = UriUtils.merge(baseUri, uri2, uri3, uri4)
then:
uri5.toString() == "http://localhost:8080/baseUrl/resource/1/count"
}
def "explodes URIs correctly"() {
given:
// (absolute) URI of the base resource
def baseUri = new URI("http://localhost:8080/baseUrl")
// (absolute) URI of the full resource to get a path to
def resourceUri = new URI("http://localhost:8080/baseUrl/resource/1/property")
when:
def uris = UriUtils.explode(baseUri, resourceUri)
then:
uris.size() == 3
uris[2].path == "property"
}
}

View File

@@ -0,0 +1,18 @@
<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework.data.services" level="DEBUG"/>
<logger name="org.springframework" level="INFO"/>
<root level="INFO">
<appender-ref ref="stdout"/>
</root>
</configuration>