/* * Copyright 2017 MongoDB, Inc. * * 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.bson.codecs.pojo; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This model represents the metadata for a class and all its fields. * * @param <T> The type of the class the ClassModel represents * @since 3.5 */ public final class ClassModel<T> { private final String name; private final Class<T> type; private final boolean hasTypeParameters; private final InstanceCreatorFactory<T> instanceCreatorFactory; private final boolean discriminatorEnabled; private final String discriminatorKey; private final String discriminator; private final FieldModel<?> idField; private final List<FieldModel<?>> fieldModels; private final Map<String, TypeParameterMap> fieldNameToTypeParameterMap; private final Map<String, FieldModel<?>> fieldMap; ClassModel(final Class<T> clazz, final Map<String, TypeParameterMap> fieldNameToTypeParameterMap, final InstanceCreatorFactory<T> instanceCreatorFactory, final Boolean discriminatorEnabled, final String discriminatorKey, final String discriminator, final FieldModel<?> idField, final List<FieldModel<?>> fieldModels) { this.name = clazz.getSimpleName(); this.type = clazz; this.hasTypeParameters = clazz.getTypeParameters().length > 0; this.fieldNameToTypeParameterMap = fieldNameToTypeParameterMap; this.instanceCreatorFactory = instanceCreatorFactory; this.discriminatorEnabled = discriminatorEnabled; this.discriminatorKey = discriminatorKey; this.discriminator = discriminator; this.idField = idField; this.fieldModels = fieldModels; this.fieldMap = generateFieldMap(fieldModels); } /** * Creates a new Class Model builder instance using reflection. * * @param type the POJO class to reflect and configure the builder with. * @param <S> the type of the class * @return a new Class Model builder instance using reflection on the {@code clazz}. */ public static <S> ClassModelBuilder<S> builder(final Class<S> type) { return new ClassModelBuilder<S>(type); } /** * @return a new InstanceCreator instance for the ClassModel */ InstanceCreator<T> getInstanceCreator() { return instanceCreatorFactory.create(); } /** * @return the backing class for the ClassModel */ public Class<T> getType() { return type; } /** * @return true if the underlying type has type parameters. */ public boolean hasTypeParameters() { return hasTypeParameters; } /** * @return true if a discriminator should be used when storing the data. */ public boolean useDiscriminator() { return discriminatorEnabled; } /** * Gets the value for the discriminator. * * @return the discriminator value or null if not set */ public String getDiscriminatorKey() { return discriminatorKey; } /** * Returns the discriminator key. * * @return the discriminator key or null if not set */ public String getDiscriminator() { return discriminator; } /** * Gets a field by the document field name. * * @param documentFieldName the fieldModel's document name * @return the field or null if the field is not found */ public FieldModel<?> getFieldModel(final String documentFieldName) { return fieldMap.get(documentFieldName); } /** * Returns all the fields on this model * * @return the list of fields */ public List<FieldModel<?>> getFieldModels() { return fieldModels; } /** * Returns the {@link FieldModel} mapped as the id field for this ClassModel * * @return the FieldModel for the id */ public FieldModel<?> getIdFieldModel() { return idField; } /** * Returns the name of the class represented by this ClassModel * * @return the name */ public String getName() { return name; } @Override public String toString() { return "ClassModel{" + "type=" + type + "}"; } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } ClassModel<?> that = (ClassModel<?>) o; if (discriminatorEnabled != that.discriminatorEnabled) { return false; } if (!getType().equals(that.getType())) { return false; } if (!getInstanceCreatorFactory().equals(that.getInstanceCreatorFactory())) { return false; } if (getDiscriminatorKey() != null ? !getDiscriminatorKey().equals(that.getDiscriminatorKey()) : that.getDiscriminatorKey() != null) { return false; } if (getDiscriminator() != null ? !getDiscriminator().equals(that.getDiscriminator()) : that.getDiscriminator() != null) { return false; } if (idField != null ? !idField.equals(that.idField) : that.idField != null) { return false; } if (!getFieldModels().equals(that.getFieldModels())) { return false; } if (!getFieldNameToTypeParameterMap().equals(that.getFieldNameToTypeParameterMap())) { return false; } return true; } @Override public int hashCode() { int result = getType().hashCode(); result = 31 * result + getInstanceCreatorFactory().hashCode(); result = 31 * result + (discriminatorEnabled ? 1 : 0); result = 31 * result + (getDiscriminatorKey() != null ? getDiscriminatorKey().hashCode() : 0); result = 31 * result + (getDiscriminator() != null ? getDiscriminator().hashCode() : 0); result = 31 * result + (idField != null ? idField.hashCode() : 0); result = 31 * result + getFieldModels().hashCode(); result = 31 * result + getFieldNameToTypeParameterMap().hashCode(); return result; } InstanceCreatorFactory<T> getInstanceCreatorFactory() { return instanceCreatorFactory; } Map<String, TypeParameterMap> getFieldNameToTypeParameterMap() { return fieldNameToTypeParameterMap; } private static Map<String, FieldModel<?>> generateFieldMap(final List<FieldModel<?>> fieldModels) { Map<String, FieldModel<?>> fieldMap = new HashMap<String, FieldModel<?>>(); for (FieldModel<?> fieldModel : fieldModels) { fieldMap.put(fieldModel.getDocumentFieldName(), fieldModel); } return fieldMap; } }