/* * Copyright 2004-2009 the original author or authors. * * 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.compass.core.config.process; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.SortedSet; import org.compass.core.config.CompassSettings; import org.compass.core.converter.Converter; import org.compass.core.converter.ConverterLookup; import org.compass.core.engine.naming.PropertyNamingStrategy; import org.compass.core.mapping.AliasMapping; import org.compass.core.mapping.CompassMapping; import org.compass.core.mapping.Mapping; import org.compass.core.mapping.MappingException; import org.compass.core.mapping.OverrideByNameMapping; import org.compass.core.mapping.osem.AbstractCollectionMapping; import org.compass.core.mapping.osem.ArrayMapping; import org.compass.core.mapping.osem.ClassMapping; import org.compass.core.mapping.osem.CollectionMapping; import org.compass.core.mapping.osem.LazyMapping; import org.compass.core.mapping.osem.ObjectMapping; import org.compass.core.mapping.osem.internal.InternalLazyMapping; /** * Goes over all the OSEM {@link org.compass.core.mapping.osem.ClassMapping}s. For each * class mappings, goes over all of its mappings and checks if they represent a collection/array. * If they represent a collection/array, wraps them with either a {@link org.compass.core.mapping.osem.CollectionMapping} * or an {@link org.compass.core.mapping.osem.ArrayMapping}. Copies over the mappings types and set it as the * collection/array element mapping. * * <p>A note on element mapping: Compass simplifies mappings for collection. There is no need for different * property/component/reference mappings when handling collections/arrays. So, the actual mappings (property/ * component/reference) actually refers to the element mapping, which is why the mapping constructed is copied * over as the element mapping. * * @author kimchy */ public class CollectionMappingProcessor implements MappingProcessor { private ConverterLookup converterLookup; public CompassMapping process(CompassMapping compassMapping, PropertyNamingStrategy namingStrategy, ConverterLookup converterLookup, CompassSettings settings) throws MappingException { this.converterLookup = converterLookup; ArrayList colMappingsToAdd = new ArrayList(); for (AliasMapping aliasMapping : compassMapping.getMappings()) { if (!(aliasMapping instanceof ClassMapping)) { continue; } colMappingsToAdd.clear(); ClassMapping classMapping = (ClassMapping) aliasMapping; for (Iterator it = classMapping.mappingsIt(); it.hasNext();) { Mapping mapping = (Mapping) it.next(); if ((mapping instanceof ObjectMapping)) { ObjectMapping objectMapping = (ObjectMapping) mapping; if (objectMapping.canBeCollectionWrapped()) { Mapping maybeColMapping = checkCollection(objectMapping); // check if we wrapped the mapping as a collection, if we did // remove id and re-add it later if (maybeColMapping instanceof AbstractCollectionMapping) { colMappingsToAdd.add(maybeColMapping); it.remove(); } } } } for (Iterator it = colMappingsToAdd.iterator(); it.hasNext();) { Mapping mapping = (Mapping) it.next(); classMapping.addMapping(mapping); } } return compassMapping; } /** * An attibute/component/reference might be a collection/array. The method * check if they represent a collection, and if they are, configures a * collection mapping with them as the collection element mapping. */ private Mapping checkCollection(ObjectMapping objectMapping) throws MappingException { AbstractCollectionMapping collectionMapping = null; Class collectionClass = objectMapping.getGetter().getReturnType(); if (Collection.class.isAssignableFrom(collectionClass)) { collectionMapping = new CollectionMapping(); if (List.class.isAssignableFrom(collectionClass)) { collectionMapping.setCollectionType(AbstractCollectionMapping.CollectionType.LIST); } else if (LinkedHashSet.class.isAssignableFrom(collectionClass)) { collectionMapping.setCollectionType(AbstractCollectionMapping.CollectionType.LINKED_HASH_SET); } else if (EnumSet.class.isAssignableFrom(collectionClass)) { collectionMapping.setCollectionType(AbstractCollectionMapping.CollectionType.ENUM_SET); } else if (SortedSet.class.isAssignableFrom(collectionClass)) { collectionMapping.setCollectionType(AbstractCollectionMapping.CollectionType.SORTED_SET); } else if (Set.class.isAssignableFrom(collectionClass)) { collectionMapping.setCollectionType(AbstractCollectionMapping.CollectionType.SET); } else { collectionMapping.setCollectionType(AbstractCollectionMapping.CollectionType.UNKNOWN); } } else if (collectionClass.isArray()) { Converter converter = converterLookup.lookupConverter(objectMapping.getGetter().getReturnType()); if (converter == null) { // there is no converter assigned to that array, use the array // mapping to convert each element inside, otherwise the // converter will be responsible to convert the whole array collectionMapping = new ArrayMapping(); collectionMapping.setCollectionType(AbstractCollectionMapping.CollectionType.NOT_REQUIRED); } } if (collectionMapping != null) { collectionMapping.setElementMapping(objectMapping); // setting the collection (the same as the inner element mapping) collectionMapping.setGetter(objectMapping.getGetter()); collectionMapping.setSetter(objectMapping.getSetter()); collectionMapping.setName(objectMapping.getName()); collectionMapping.setPath(objectMapping.getPath()); collectionMapping.setPropertyName(objectMapping.getPropertyName()); collectionMapping.setDefinedInAlias(objectMapping.getDefinedInAlias()); if (objectMapping instanceof OverrideByNameMapping) { collectionMapping.setOverrideByName(((OverrideByNameMapping) objectMapping).isOverrideByName()); } else { collectionMapping.setOverrideByName(true); } if ((collectionMapping instanceof LazyMapping) && (objectMapping instanceof LazyMapping)) { ((InternalLazyMapping) collectionMapping).setLazy(((LazyMapping) objectMapping).isLazy()); } return collectionMapping; } else { return objectMapping; } } }