Java tutorial
/* * Copyright (c) 2014 Alexander Gulko <kirhog at gmail dot com>. * * 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 org.fastmongo.odm.dbobject.mapping.support.classname; import com.mongodb.DBObject; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.reflections.Reflections; import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import static org.fastmongo.odm.dbobject.mapping.core.ConverterHelper.CLASS_KEY; import static org.fastmongo.odm.dbobject.mapping.core.ConverterHelper.restoreClassName; /** * Implementation of classes names resolver interface using reflections. * Uses as additional condition to get classes names. * * @author Alexander Gulko */ public class ReflectionClassNameResolver implements ClassNameResolver { private static final Map<Class<?>, String> IMPLEMENTATION_BY_INTERFACE = new ConcurrentHashMap<>(); private static final String NO_IMPLEMENTATION = ""; private static final Map<Type, ResolveStrategy> STRATEGY_BY_CLASS = new ConcurrentHashMap<>(); private List<ResolveStrategy> resolveStrategies; private Reflections reflections; public ReflectionClassNameResolver(String basePackage, List<ResolveStrategy> resolveStrategies) { this.resolveStrategies = resolveStrategies; reflections = new Reflections(basePackage, new SubTypesScanner()); } @Override @SuppressWarnings("unchecked") public String getClassName(Type type, DBObject dbObject, String classPrefix) { if (dbObject.containsField(CLASS_KEY)) { return restoreClassName((String) dbObject.get(CLASS_KEY), classPrefix); } Class clazz = (Class) type; String className = IMPLEMENTATION_BY_INTERFACE.get(clazz); if (className == null) { Set<Class<?>> subTypes = reflections.getSubTypesOf(clazz); if (subTypes.size() == 1) { className = subTypes.iterator().next().getName(); } else { className = NO_IMPLEMENTATION; } IMPLEMENTATION_BY_INTERFACE.put(clazz, className); } if (!NO_IMPLEMENTATION.equals(className)) { return className; } ResolveStrategy resolveStrategy = findSuitableStrategy(clazz); if (resolveStrategy != null) { className = resolveStrategy.getClassName(clazz, dbObject); className = className.startsWith(classPrefix) ? className : restoreClassName(className, classPrefix); } if (StringUtils.isEmpty(className)) { if (!clazz.isInterface()) { return clazz.getName(); } throw new IllegalArgumentException(String.format( "Can't find appropriate class name for '%s' and DBObject('%s') with classNamePrefix = %s", type, StringUtils.abbreviateMiddle(dbObject.toString(), "<...>", 100), classPrefix)); } return className; } @Override public boolean isWriteClassName(Type type) { ResolveStrategy resolveStrategy = findSuitableStrategy(type); return resolveStrategy != null && resolveStrategy.isWriteClassName(type); } @Override public boolean isWriteClassNameToLinks(Type type) { ResolveStrategy resolveStrategy = findSuitableStrategy(type); return resolveStrategy != null && resolveStrategy.isWriteClassNameToLinks(type); } private ResolveStrategy findSuitableStrategy(Type type) { if (!CollectionUtils.isEmpty(resolveStrategies)) { ResolveStrategy strategy = STRATEGY_BY_CLASS.get(type); if (strategy == null) { for (ResolveStrategy resolveStrategy : resolveStrategies) { if (resolveStrategy.isSuitableStrategy(type)) { strategy = resolveStrategy; STRATEGY_BY_CLASS.put(type, strategy); break; } } } return strategy; } return null; } }