/*
* 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.lang.reflect.Modifier;
import java.util.Iterator;
import org.compass.core.accessor.PropertyAccessor;
import org.compass.core.accessor.PropertyAccessorFactory;
import org.compass.core.config.CompassSettings;
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.MultipleMapping;
import org.compass.core.mapping.osem.ClassMapping;
import org.compass.core.mapping.osem.ObjectMapping;
import org.compass.core.mapping.osem.internal.InternalObjectMapping;
import org.compass.core.util.reflection.ReflectionFactory;
/**
* <p>Goes through each {@link org.compass.core.mapping.osem.ClassMapping} and resolves
* its reflection settings (constructor, getter, setter, and object class).
*
* <p>Since this processor happens before the flattening of the mappings, it is not
* required to follow the ref aliases for component and reference mappings.
*
* @author kimchy
*/
public class PropertyAccessorMappingProcessor implements MappingProcessor {
private PropertyAccessorFactory propertyAccessorFactory;
public CompassMapping process(CompassMapping compassMapping, PropertyNamingStrategy namingStrategy,
ConverterLookup converterLookup, CompassSettings settings) throws MappingException {
// initalize the property accessor registry
propertyAccessorFactory = new PropertyAccessorFactory();
propertyAccessorFactory.configure(settings);
for (AliasMapping aliasMapping : compassMapping.getMappings()) {
if (aliasMapping instanceof ClassMapping) {
ClassMapping classMapping = (ClassMapping) aliasMapping;
// resolve the class mapping constructor
classMapping.setConstructor(ReflectionFactory.getDefaultConstructor(settings, classMapping.getClazz()));
// if it is not abstract and not an interface, it must have a default constructor
if (!Modifier.isAbstract(classMapping.getClazz().getModifiers()) && !Modifier.isInterface(classMapping.getClazz().getModifiers()) && !classMapping.getClazz().isEnum()) {
if (classMapping.getConstructor() == null) {
throw new MappingException("No default constructor defined for class [" + classMapping.getName() + "]");
}
}
if (classMapping.getPolyClass() != null) {
classMapping.setPolyConstructor(ReflectionFactory.getDefaultConstructor(settings, classMapping.getPolyClass()));
}
Class clazz = classMapping.getClazz();
if (classMapping.isPoly() && classMapping.getPolyClass() != null) {
clazz = classMapping.getPolyClass();
}
for (Iterator it = classMapping.mappingsIt(); it.hasNext();) {
processMapping((Mapping) it.next(), clazz, settings);
}
}
}
return compassMapping;
}
private void processMapping(Mapping mapping, Class clazz, CompassSettings settings)
throws MappingException {
if (!(mapping instanceof ObjectMapping)) {
return;
}
ObjectMapping objectMapping = (ObjectMapping) mapping;
PropertyAccessor pAccessor = propertyAccessorFactory.getPropertyAccessor(objectMapping.getAccessor(), settings);
((InternalObjectMapping) objectMapping).setGetter(pAccessor.getGetter(clazz, objectMapping.getPropertyName()));
((InternalObjectMapping) objectMapping).setSetter(pAccessor.getSetter(clazz, objectMapping.getPropertyName()));
if (mapping instanceof MultipleMapping) {
MultipleMapping multipleMapping = (MultipleMapping) mapping;
for (Iterator it = multipleMapping.mappingsIt(); it.hasNext();) {
processMapping((Mapping) it.next(), clazz, settings);
}
}
}
}