/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 net.formio.binding.collection;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import net.formio.binding.BindingReflectionUtils;
/**
* Builds various common collections and arrays from given specification
* (collection class and ordering of items) and given items.
* Different subclasses with different registered collection builders can be
* created: Method {@link #registerBuilders()} can be overridden.
*
* @author Radek Beran
*/
public class BasicCollectionBuilders implements CollectionBuilders {
/**
* Intentionally left default constructor, that can be used with dependency
* injection. Subclasses can define and inject their own mechanisms to
* build collections.
*/
public BasicCollectionBuilders() {
}
@Override
public <C, I> C buildCollection(CollectionSpec<C> collSpec, Class<I> itemClass, List<I> items) {
ensureBuildersRegistered();
CollectionSpec<C> cSpec = null;
if (collSpec.getCollClass().isArray()) {
cSpec = (CollectionSpec<C>)CollectionSpec.getInstance(Array.class, collSpec.getPreferedItemsOrder());
} else {
cSpec = collSpec;
}
CollectionBuilder<C> collBuilder = (CollectionBuilder<C>)BUILDERS_CACHE.get(cSpec);
if (collBuilder == null)
throw new CollectionBuilderNotFoundException(cSpec);
return collBuilder.build(itemClass, items);
}
@Override
public boolean canHandle(CollectionSpec<?> collSpec) {
ensureBuildersRegistered();
return collSpec.getCollClass().isArray() || BUILDERS_CACHE.get(collSpec) != null;
}
@Override
public Class<?> getItemClass(Class<?> parentClass, String propertyName, Type genericCollectionType) {
return BindingReflectionUtils.itemTypeFromGenericCollType(genericCollectionType);
}
protected Map<CollectionSpec<?>, CollectionBuilder<?>> registerBuilders() {
if (BUILDERS_CACHE.isEmpty()) {
BUILDERS_CACHE.put(CollectionSpec.getInstance(List.class, ItemsOrder.LINEAR), ListBuilder.LINEAR);
BUILDERS_CACHE.put(CollectionSpec.getInstance(ArrayList.class, ItemsOrder.LINEAR), ListBuilder.LINEAR);
BUILDERS_CACHE.put(CollectionSpec.getInstance(Set.class, ItemsOrder.LINEAR), SetBuilder.LINEAR);
BUILDERS_CACHE.put(CollectionSpec.getInstance(Set.class, ItemsOrder.HASH), SetBuilder.HASH);
BUILDERS_CACHE.put(CollectionSpec.getInstance(Set.class, ItemsOrder.SORTED), SetBuilder.SORTED);
BUILDERS_CACHE.put(CollectionSpec.getInstance(LinkedHashSet.class, ItemsOrder.LINEAR), SetBuilder.LINEAR);
BUILDERS_CACHE.put(CollectionSpec.getInstance(HashSet.class, ItemsOrder.HASH), SetBuilder.HASH);
BUILDERS_CACHE.put(CollectionSpec.getInstance(TreeSet.class, ItemsOrder.SORTED), SetBuilder.SORTED);
BUILDERS_CACHE.put(CollectionSpec.getInstance(Collection.class, ItemsOrder.LINEAR), ListBuilder.LINEAR);
// Note: Array is auxiliary class for arrays, expected by buildCollection
BUILDERS_CACHE.put(CollectionSpec.getInstance(Array.class, ItemsOrder.LINEAR), ArrayBuilder.LINEAR);
BUILDERS_CACHE.put(CollectionSpec.getInstance(Array.class, ItemsOrder.SORTED), ArrayBuilder.SORTED);
}
return BUILDERS_CACHE;
}
private void ensureBuildersRegistered() {
if (BUILDERS_CACHE.isEmpty()) registerBuilders();
}
private static final Map<CollectionSpec<?>, CollectionBuilder<?>> BUILDERS_CACHE = new ConcurrentHashMap<CollectionSpec<?>, CollectionBuilder<?>>();
}