io.github.pustike.persist.metadata.EntityData Maven / Gradle / Ivy
/*
* Copyright (C) 2016-2019 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
*
* https://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 io.github.pustike.persist.metadata;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.github.pustike.persist.FieldGroup;
/**
* The entity metadata.
*/
public final class EntityData {
private final Class> entityClass;
private final String tableName;
private final Set declaredFieldData;
private Map fieldDataMap;
private EntityData parentEntity;
private FieldData idField, versionField;
private String joinFieldGroup;
private Map> fieldGroupData;
EntityData(Class> entityClass, String tableName) {
this.entityClass = entityClass;
this.tableName = tableName;
this.declaredFieldData = new LinkedHashSet<>();
}
/**
* Get the entity class using which this metadata is created.
* @return the entity class
*/
public Class> getEntityClass() {
return entityClass;
}
/**
* Get the table name for this entity. It can be {@code null} if this is a super class.
* @see #isSuperClass()
* @return the name of the table
*/
public String getTableName() {
return tableName;
}
/**
* Get the parent entity metadata, if present.
* @return the parent entity metadata.
*/
public EntityData getParentEntity() {
return parentEntity;
}
void setParentEntity(EntityData entityData) {
this.parentEntity = entityData;
}
/**
* Get the @{@link io.github.pustike.persist.Id} field metadata of this entity.
* @return the id field metadata of this entity
*/
public FieldData getIdField() {
return idField;
}
private void setIdField(FieldData fieldData) {
if (this.idField != null) {
throw new IllegalStateException("multiple @Id columns can not be present in an entity");
}
this.idField = fieldData;
}
/**
* Get the @{@link io.github.pustike.persist.Version} field metadata of this entity.
* @return the version field metadata of this entity
*/
public FieldData getVersionField() {
return versionField;
}
private void setVersionField(FieldData fieldData) {
if (this.versionField != null) {
throw new IllegalStateException("multiple @Version columns can not be present in an entity");
}
this.versionField = fieldData;
}
void addField(FieldData fieldData) {
fieldData.validate();
declaredFieldData.add(fieldData);
}
/**
* Get a set of declared field metadata directly on this entity.
* @return a set of field metadata declared
*/
public Set getDeclaredFieldData() {
return Collections.unmodifiableSet(declaredFieldData);
}
/**
* Get the field metadata for the given field name
* @param fieldName the name of the field
* @return the corresponding field metadata
*/
public FieldData getFieldData(String fieldName) {
FieldData fieldData = fieldDataMap.get(fieldName);
if (fieldData == null) {
throw new RuntimeException("FieldData is not available for field: " + fieldName + " in : " + entityClass);
}
return fieldData;
}
void validate() {
List fieldDataList = new ArrayList<>(declaredFieldData);
if (parentEntity != null) {
fieldDataList.addAll(parentEntity.getFieldData());
}
fieldDataList.sort((o1, o2) -> {
ColumnType type1 = o1.getColumnType(), type2 = o2.getColumnType();
return type1 == ColumnType.Id ? -1 : type2 == ColumnType.Id ? 1 : type1 == ColumnType.Version ? 1
: type2 == ColumnType.Version ? -1 : o1.getColumnName().compareTo(o2.getColumnName());
});
Map _fieldDataMap = new LinkedHashMap<>();
for (FieldData fieldData : fieldDataList) {
if (fieldData.getColumnType() == ColumnType.Id) {
setIdField(fieldData);
} else if (fieldData.getColumnType() == ColumnType.Version) {
setVersionField(fieldData);
}
_fieldDataMap.put(fieldData.getName(), fieldData);
}
if (idField == null && !isSuperClass()) {
throw new IllegalStateException("The @Table must have an @Id field for table: " + tableName);
}
this.fieldDataMap = Collections.unmodifiableMap(_fieldDataMap);
readFieldGroupData();
}
/**
* Get a collection of all field metadata, including that of parent entity.
* @return the collection of all field metadata
*/
public Collection getFieldData() {
return fieldDataMap.values();
}
/**
* Check if this entity metadata is of a super class. {@code true} if the table name is {@code null}.
* @return true if this metadata is from a super class
*/
public boolean isSuperClass() {
return tableName == null;
}
private void readFieldGroupData() {
this.fieldGroupData = new HashMap<>();
Set fetchFieldNames = createFieldNames();
for (FieldData fieldData : getFieldData()) {
if (fieldData.isFetch()) {
fetchFieldNames.add(fieldData.getName());
}
}
this.fieldGroupData.put(null, fetchFieldNames);
FieldGroup[] fieldGroups = entityClass.getDeclaredAnnotationsByType(FieldGroup.class);
if (fieldGroups == null) {
return;
}
Map fieldGroupMap = new LinkedHashMap<>();
for (FieldGroup fieldGroup : fieldGroups) {
if (fieldGroup.joinFetch()) {
if (joinFieldGroup != null) {
throw new IllegalStateException("Fetch Group with joinFetch can only be used once!: " + tableName);
}
joinFieldGroup = fieldGroup.name();
}
FieldGroup oldValue = fieldGroupMap.put(fieldGroup.name(), fieldGroup);
if (oldValue != null) {
throw new IllegalStateException("Fetch Group name should be unique for: " + tableName);
}
}
for (FieldGroup fieldGroup : fieldGroupMap.values()) {
Set fieldNames = createFieldNames();
for (String include : fieldGroup.includes()) {
Set includeFieldNames = fieldGroupData.get(include);
if (includeFieldNames == null) {
throw new IllegalStateException("Included Fetch Group: " + include + " not found on " + tableName);
}
fieldNames.addAll(includeFieldNames);
}
fieldNames.addAll(Arrays.asList(fieldGroup.fields()));
fieldGroupData.put(fieldGroup.name(), Collections.unmodifiableSet(fieldNames));
}
}
private Set createFieldNames() {
LinkedHashSet fieldNames = new LinkedHashSet<>();
fieldNames.add(idField.getName());
if (versionField != null) {
fieldNames.add(versionField.getName());
}
return fieldNames;
}
/**
* Get a set fields to be fetched during join. @{@link io.github.pustike.persist.Id} field is included always.
* @param joinGroup the join group to be used, can be {@code null}
* @return the set of join fetch fields
*/
public Set getJoinFetchFields(String joinGroup) {
Set joinFetchFields = new LinkedHashSet<>();
joinFetchFields.add(idField.getName());
String fieldGroup = joinGroup == null ? this.joinFieldGroup : joinGroup;
if (fieldGroup != null) {
joinFetchFields.addAll(getFieldGroupFields(fieldGroup));
}
return Collections.unmodifiableSet(joinFetchFields);
}
/**
* Get the set of fields for the given fieldGroup, declared on this entity.
* @param fieldGroup the name of the fieldGroup
* @return the set of field names defined in this group
*/
public Set getFieldGroupFields(String fieldGroup) {
Set fieldGroupFields = fieldGroupData.get(fieldGroup);
if (fieldGroupFields == null) {
throw new IllegalStateException("Field Group: " + fieldGroup + " not found on " + tableName);
}
return fieldGroupFields;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy