
co.cask.cdap.common.lang.InstantiatorFactory Maven / Gradle / Ivy
/*
* Copyright © 2014 Cask Data, Inc.
*
* 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 co.cask.cdap.common.lang;
import co.cask.cdap.internal.lang.Reflections;
import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.reflect.TypeToken;
import sun.misc.Unsafe;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
/**
* InstantiatorFactory.
*/
@SuppressWarnings("unchecked")
public final class InstantiatorFactory {
private static final Unsafe UNSAFE;
private final LoadingCache, Instantiator>> instantiatorCache;
static {
Unsafe unsafe;
try {
Class> unsafeClass = Class.forName("sun.misc.Unsafe");
Field f = unsafeClass.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (Unsafe) f.get(null);
} catch (Exception e) {
unsafe = null;
}
UNSAFE = unsafe;
}
public InstantiatorFactory(final boolean useKnownType) {
instantiatorCache = CacheBuilder.newBuilder().build(new CacheLoader, Instantiator>>() {
@Override
public Instantiator> load(TypeToken> type) throws Exception {
Instantiator> creator = getByDefaultConstructor(type);
if (creator != null) {
return creator;
}
if (useKnownType) {
creator = getByKnownType(type);
if (creator != null) {
return creator;
}
}
return getByUnsafe(type);
}
});
}
public Instantiator get(TypeToken type) {
return (Instantiator) instantiatorCache.getUnchecked(type);
}
/**
* Returns an {@link Instantiator} that uses default constructor to instantiate an object of the given type.
*
* @param type
* @param
*/
private Instantiator getByDefaultConstructor(TypeToken type) {
try {
final Constructor super T> defaultCons = type.getRawType().getDeclaredConstructor();
defaultCons.setAccessible(true);
return new Instantiator() {
@Override
public T create() {
try {
return (T) defaultCons.newInstance();
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
};
} catch (NoSuchMethodException e) {
return null;
}
}
private Instantiator getByKnownType(TypeToken type) {
Class super T> rawType = type.getRawType();
if (rawType.isArray()) {
return new Instantiator() {
@Override
public T create() {
return (T) Lists.newLinkedList();
}
};
}
if (Collection.class.isAssignableFrom(rawType)) {
if (SortedSet.class.isAssignableFrom(rawType)) {
return new Instantiator() {
@Override
public T create() {
return (T) Sets.newTreeSet();
}
};
}
if (Set.class.isAssignableFrom(rawType)) {
return new Instantiator() {
@Override
public T create() {
return (T) Sets.newHashSet();
}
};
}
if (Queue.class.isAssignableFrom(rawType)) {
return new Instantiator() {
@Override
public T create() {
return (T) Lists.newLinkedList();
}
};
}
return new Instantiator() {
@Override
public T create() {
return (T) Lists.newArrayList();
}
};
}
if (Map.class.isAssignableFrom(rawType)) {
if (SortedMap.class.isAssignableFrom(rawType)) {
return new Instantiator() {
@Override
public T create() {
return (T) Maps.newTreeMap();
}
};
}
return new Instantiator() {
@Override
public T create() {
return (T) Maps.newHashMap();
}
};
}
return null;
}
private Instantiator getByUnsafe(final TypeToken type) {
return new Instantiator() {
@Override
public T create() {
try {
Object instance = UNSAFE.allocateInstance(type.getRawType());
Reflections.visit(instance, type.getType(), new FieldInitializer());
return (T) instance;
} catch (InstantiationException e) {
throw Throwables.propagate(e);
}
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy