/** * 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.deephacks.confit.serialization; import com.google.common.base.Optional; import org.deephacks.confit.Config; import org.deephacks.confit.Id; import org.deephacks.confit.Index; import org.deephacks.confit.model.Events; import org.deephacks.confit.model.Schema.AbstractSchemaProperty; import org.deephacks.confit.model.Schema.SchemaProperty; import org.deephacks.confit.model.Schema.SchemaPropertyList; import org.deephacks.confit.model.Schema.SchemaPropertyRef; import org.deephacks.confit.model.Schema.SchemaPropertyRefList; import org.deephacks.confit.model.Schema.SchemaPropertyRefMap; import org.deephacks.confit.serialization.ClassToSchemaConverter.ConfigClass; import org.deephacks.confit.serialization.Conversion.ConversionException; import org.deephacks.confit.serialization.Conversion.Converter; import org.deephacks.confit.serialization.Reflections.ClassIntrospector; import org.deephacks.confit.serialization.Reflections.ClassIntrospector.FieldWrap; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.List; import static org.deephacks.confit.model.Events.CFG104_UNSUPPORTED_PROPERTY; import static org.deephacks.confit.model.Events.CFG109_ILLEGAL_MAP; final class FieldToSchemaPropertyConverter implements Converter<FieldWrap, AbstractSchemaProperty> { private Conversion conversion = Conversion.get(); @Override public AbstractSchemaProperty convert(FieldWrap source, Class<? extends AbstractSchemaProperty> specificType) { if (source.isMap()) { List<Class<?>> types = source.getMapParamTypes(); if (!String.class.equals(types.get(0))) { throw CFG109_ILLEGAL_MAP(source.getFieldName()); } if (!types.get(1).isAnnotationPresent(Config.class)) { throw CFG109_ILLEGAL_MAP(source.getFieldName()); } return convertReferences(source); } if (source.isArray()) { throw new IllegalArgumentException("Arrays are not supported, use java.util.Collection instead: " + source.getField()); } Class<?> type = source.getType(); if (type.isAnnotationPresent(Config.class)) { return convertReferences(source); } else { return convertSimple(source); } } private AbstractSchemaProperty convertSimple(FieldWrap source) { Optional<Annotation> annotation = source.getAnnotation(); ConfigClass configClass = new ConfigClass(); if (annotation.isPresent()) { Config config = (Config) annotation.get(); configClass.name = config.name(); configClass.desc = config.desc(); } else { configClass.name = source.getFieldName(); configClass.desc = ""; } String name = configClass.name; String desc = configClass.desc; String fieldName = source.getFieldName(); boolean indexed = source.isAnnotationPresent(Index.class); if (name == null || "".equals(name)) { name = fieldName; } Class<?> type = source.getType(); validateField(source); try { if (source.isCollection()) { Collection<String> converted = conversion.convert(source.getDefaultValues(), String.class); List<String> defaultValues = new ArrayList<>(converted); return SchemaPropertyList.create(name, fieldName, type.getName(), desc, source .isFinal(), source.getEnums(), defaultValues, source.getCollRawType() .getName(), indexed); } else { return SchemaProperty.create(name, fieldName, type.getName(), desc, source.isFinal(), source.getEnums(), conversion.convert(source.getDefaultValue(), String.class), indexed); } } catch (ConversionException e) { throw CFG104_UNSUPPORTED_PROPERTY(String.class, name, type); } } private AbstractSchemaProperty convertReferences(FieldWrap source) { Optional<Annotation> optional = source.getAnnotation(); ConfigClass config = new ConfigClass(); if (optional.isPresent()) { Config cfg = (Config) optional.get(); config.name = cfg.name(); config.desc = cfg.desc(); } else { config.name = source.getFieldName(); config.desc = ""; } String name = config.name; String desc = config.desc; String fieldName = source.getFieldName(); boolean indexed = source.isAnnotationPresent(Index.class); if (name == null || "".equals(name)) { name = fieldName; } Class<?> type = source.getType(); if (source.isCollection()) { return SchemaPropertyRefList.create(name, fieldName, getSchemaName(type), type, desc, source.isFinal(), source.getCollRawType().getName(), indexed); } else if (source.isMap()) { // type is contained in parameterized value of the map type = source.getMapParamTypes().get(1); return SchemaPropertyRefMap.create(name, fieldName, getSchemaName(type), type, desc, source.isFinal(), source.getMapRawType().getName(), indexed); } else { return SchemaPropertyRef.create(name, fieldName, getSchemaName(type), type, desc, source.isFinal(), isSingleton(type), indexed); } } private String getSchemaName(Class<?> type) { Config configurable = type.getAnnotation(Config.class); String schemaName = configurable.name(); if (schemaName == null || "".equals(schemaName)) { schemaName = type.getName(); } return schemaName; } private boolean isSingleton(Class<?> field) { ClassIntrospector introspector = new ClassIntrospector(field); return introspector.getFieldList(Id.class).size() == 0; } private void validateField(FieldWrap field) { if (field.isStatic() && !field.isFinal()) { // non-final static @Property not supported. throw Events.CFG108_ILLEGAL_MODIFIERS(field.getField()); } if (field.isTransient()) { // transient @Property not supported. throw Events.CFG108_ILLEGAL_MODIFIERS(field.getField()); } } }