Skip to content

Instantly share code, notes, and snippets.

@esmasui
Last active August 29, 2015 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save esmasui/d7854840597ad6cc2707 to your computer and use it in GitHub Desktop.
Save esmasui/d7854840597ad6cc2707 to your computer and use it in GitHub Desktop.
NullObjectぱてーん
package com.example;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public abstract class CollectionUtils {
private CollectionUtils() {
throw new UnsupportedOperationException("No instances");
}
public static int[] intCollectionToPrimitiveArray(Collection<Integer> collection) {
final Iterator<Integer> iterator = collection.iterator();
final int[] primitives = new int[collection.size()];
for (int i = 0, length = primitives.length; i < length; ++i) {
primitives[i] = iterator.next();
}
return primitives;
}
public static long[] longCollectionToPrimitiveArray(Collection<Long> collection) {
final Iterator<Long> iterator = collection.iterator();
final long[] primitives = new long[collection.size()];
for (int i = 0, length = primitives.length; i < length; ++i) {
primitives[i] = iterator.next();
}
return primitives;
}
public static <S, T> T[] copyToDestinationTypeArray(S[] src, Class<T> destinationType) {
final T[] arr = newArrayInstance(destinationType, src.length);
System.arraycopy(src, 0, arr, 0, src.length);
return arr;
}
public static <T> T[] nullToEmptyArray(T[] array, Class<?> arrayType) {
return array == null ? (T[]) Array.newInstance(arrayType, 0) : array;
}
public static <T> List<T> nullToEmptyList(T... array) {
return array == null ? Collections.<T>emptyList() : Arrays.asList(array);
}
public static <T> List<T> nullToEmptyList(List<T> list) {
return list == null ? Collections.<T>emptyList() : list;
}
public static <T> T[] objectsToArray(T... array) {
return array;
}
public static <T> T[] collectionToArray(Collection<T> collection, Class<T> destinationType) {
return collection.toArray(newArrayInstance(destinationType, collection.size()));
}
public static <T> List<T> arrayToList(T[] array) {
final ArrayList<T> list = new ArrayList<>(array.length);
for (T each : array) {
list.add(each);
}
return list;
}
public static <T> Collection<T> arrayToCollection(T[] array) {
return arrayToList(array);
}
public static <T> T[] concat(T[] a, T... b) {
final T[] arr = (T[]) newArrayInstance(a.getClass().getComponentType(), a.length + b.length);
System.arraycopy(a, 0, arr, 0, a.length);
System.arraycopy(b, 0, arr, a.length, b.length);
return arr;
}
private static <T> T[] newArrayInstance(Class<T> type, int length) {
return (T[]) Array.newInstance(type, length);
}
public static <T> int indexOf(T[] values, T value) {
for (int i = 0; i < values.length; i++) {
if (values[i].equals(value)) {
return i;
}
}
return -1;
}
}
package com.example;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.example.CollectionUtils.concat;
import static com.example.CollectionUtils.nullToEmptyArray;
import static com.example.CollectionUtils.objectsToArray;
/**
* Null objectを生成するためのファクトリーメソッドを提供するクラス
*/
public abstract class NullObjects {
public interface Producer {
Object produce(Class<?> returnType);
}
private NullObjects() {
throw new UnsupportedOperationException("No instances");
}
public static Builder builder() {
return new Builder();
}
public static Builder defaults() {
return builder().defaultValue().emptyCollection();
}
public static class Builder {
private final Set<Producer> producers = new LinkedHashSet<>();
/**
* Producer を追加する。優先順位は追加された順に依る
*
* @param producer
* @return このビルダーオブジェクト
*/
public Builder produce(Producer producer) {
producers.add(producer);
return this;
}
/**
* プリミティブ型の返り値のメソッドではデフォルト値(<a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html">Primitive Data Types</a>)を返すようにNull objectを構成する。
*
* @return このビルダーオブジェクト
*/
public Builder defaultValue() {
return produce(DEFAULT_VALUE_PRODUCER);
}
/**
* 配列、List、Set、Map型の返り値のメソッドで、それぞれ要素数0の値を返すようにNull objectを構成する。
*
* @return このビルダーオブジェクト
*/
public Builder emptyCollection() {
return produce(EMPTY_COLLECTION_PRODUCER);
}
public <T> T build(Class<T> type, Class<?>... otherTypes) {
return (T) Proxy.newProxyInstance(type.getClassLoader(), concat(objectsToArray(type), nullToEmptyArray(otherTypes, Class.class)), new NullObjectsInvocationHandler(producers.toArray(new Producer[producers.size()])));
}
}
private static class NullObjectsInvocationHandler implements InvocationHandler {
private final Producer[] producers;
private NullObjectsInvocationHandler(Producer... producers) {
this.producers = producers;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final Class<?> returnType = method.getReturnType();
for (Producer each : producers) {
final Object returnValue = each.produce(returnType);
if (returnValue != null) {
return returnValue;
}
}
return null;
}
}
private static final Producer EMPTY_COLLECTION_PRODUCER = new Producer() {
@Override
public Object produce(Class<?> returnType) {
if (returnType.isArray()) {
return Array.newInstance(returnType.getComponentType(), 0);
}
if (returnType.equals(List.class)) {
return Collections.emptyList();
}
if (returnType.equals(Set.class)) {
return Collections.emptySet();
}
if (returnType.equals(Map.class)) {
return Collections.emptyMap();
}
return null;
}
};
private static final Producer DEFAULT_VALUE_PRODUCER = new Producer() {
private Map<Class<?>, Object> primitives = new HashMap<>();
{
primitives.put(byte.class, Byte.valueOf((byte) 0));
primitives.put(short.class, Short.valueOf((short) 0));
primitives.put(int.class, Integer.valueOf(0));
primitives.put(long.class, Long.valueOf(0L));
primitives.put(float.class, Float.valueOf(0f));
primitives.put(double.class, Double.valueOf(0));
primitives.put(char.class, Character.valueOf((char) 0));
primitives.put(boolean.class, Boolean.valueOf(false));
}
@Override
public Object produce(Class<?> returnType) {
return primitives.get(returnType);
}
};
}
ProgressListener EMPTY_PROGRESS_LISTENER = NullObjects.defaults().build(ProgressListener.class);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment