Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.eclipse.jnosql.mapping.reflection.ReflectionClassConverter Maven / Gradle / Ivy
/*
* Copyright (c) 2022 Contributors to the Eclipse Foundation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
*
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
*
* Otavio Santana
*/
package org.eclipse.jnosql.mapping.reflection;
import jakarta.nosql.Convert;
import org.eclipse.jnosql.mapping.metadata.ClassConverter;
import org.eclipse.jnosql.mapping.metadata.EntityMetadata;
import org.eclipse.jnosql.mapping.metadata.FieldMetadata;
import org.eclipse.jnosql.mapping.metadata.GenericFieldMetadata;
import org.eclipse.jnosql.mapping.metadata.InheritanceMetadata;
import org.eclipse.jnosql.mapping.metadata.MappingType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import static java.util.Objects.nonNull;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
public final class ReflectionClassConverter implements ClassConverter {
private static final Logger LOGGER = Logger.getLogger(ReflectionClassConverter.class.getName());
private final Reflections reflections;
private final ConstructorMetadataBuilder constructorMetadataBuilder;
public ReflectionClassConverter() {
this.reflections = new Reflections();
this.constructorMetadataBuilder = new ConstructorMetadataBuilder(reflections);
}
@Override
public EntityMetadata apply(Class> entity) {
long start = System.currentTimeMillis();
String entityName = reflections.getEntityName(entity);
List fields = reflections.getFields(entity)
.stream().map(this::to).collect(toList());
List fieldsName = fields.stream().map(FieldMetadata::name).collect(toList());
Map nativeFieldGroupByJavaField =
getNativeFieldGroupByJavaField(fields, "", "");
Map fieldsGroupedByName = fields.stream()
.collect(collectingAndThen(toMap(FieldMetadata::name,
Function.identity()), Collections::unmodifiableMap));
Constructor> constructor = Reflections.getConstructor(entity);
InstanceSupplier instanceSupplier = () -> Reflections.newInstance(constructor);
InheritanceMetadata inheritance = reflections.getInheritance(entity).orElse(null);
boolean hasInheritanceAnnotation = reflections.hasInheritanceAnnotation(entity);
EntityMetadata mapping = DefaultEntityMetadata.builder().name(entityName)
.type(entity)
.fields(fields)
.fieldsName(fieldsName)
.instanceSupplier(instanceSupplier)
.javaFieldGroupedByColumn(nativeFieldGroupByJavaField)
.fieldsGroupedByName(fieldsGroupedByName)
.inheritance(inheritance)
.hasInheritanceAnnotation(hasInheritanceAnnotation)
.constructor(constructorMetadataBuilder.build(entity))
.build();
long end = System.currentTimeMillis() - start;
LOGGER.finest(String.format("Scanned the entity %s loaded with time of %d ms", entity.getName(), end));
return mapping;
}
private Map getNativeFieldGroupByJavaField(List fields,
String javaField, String nativeField) {
Map nativeFieldGroupByJavaField = new HashMap<>();
for (FieldMetadata field : fields) {
appendValue(nativeFieldGroupByJavaField, field, javaField, nativeField);
}
return nativeFieldGroupByJavaField;
}
private void appendValue(Map nativeFieldGroupByJavaField, FieldMetadata field,
String javaField, String nativeField) {
switch (field.mappingType()) {
case ENTITY -> appendFields(nativeFieldGroupByJavaField, field, javaField,
appendPreparePrefix(nativeField, field.name()));
case EMBEDDED -> appendFields(nativeFieldGroupByJavaField, field, javaField, nativeField);
case COLLECTION -> {
if (((GenericFieldMetadata) field).isEmbeddable()) {
Class> type = ((GenericFieldMetadata) field).elementType();
String nativeFieldAppended = appendPreparePrefix(nativeField, field.name());
appendFields(nativeFieldGroupByJavaField, field, javaField, nativeFieldAppended, type);
return;
}
appendDefaultField(nativeFieldGroupByJavaField, field, javaField, nativeField);
}
default -> appendDefaultField(nativeFieldGroupByJavaField, field, javaField, nativeField);
}
}
private void appendDefaultField(Map nativeFieldGroupByJavaField,
FieldMetadata field, String javaField, String nativeField) {
nativeFieldGroupByJavaField.put(javaField.concat(field.fieldName()),
NativeMapping.of(nativeField.concat(field.name()), field));
}
private void appendFields(Map nativeFieldGroupByJavaField,
FieldMetadata field,
String javaField, String nativeField) {
Class> type = field.type();
appendFields(nativeFieldGroupByJavaField, field, javaField, nativeField, type);
}
private void appendFields(Map nativeFieldGroupByJavaField,
FieldMetadata field, String javaField, String nativeField,
Class> type) {
Map entityMap = getNativeFieldGroupByJavaField(
reflections.getFields(type)
.stream().map(this::to).collect(toList()),
appendPreparePrefix(javaField, field.fieldName()), nativeField);
String nativeElement = entityMap.values().stream().map(NativeMapping::nativeField)
.collect(Collectors.joining(","));
nativeFieldGroupByJavaField.put(appendPrefix(javaField, field.fieldName()), NativeMapping.of(nativeElement, field));
nativeFieldGroupByJavaField.putAll(entityMap);
}
private String appendPreparePrefix(String prefix, String field) {
return appendPrefix(prefix, field).concat(".");
}
private String appendPrefix(String prefix, String field) {
if (prefix.isEmpty()) {
return field;
} else {
return prefix.concat(field);
}
}
private FieldMetadata to(Field field) {
MappingType mappingType = MappingType.of(field.getType());
reflections.makeAccessible(field);
Convert convert = field.getAnnotation(Convert.class);
boolean id = reflections.isIdField(field);
String columnName = id ? reflections.getIdName(field) : reflections.getColumnName(field);
String udt = reflections.getUDTName(field);
FieldMappingBuilder builder = new FieldMappingBuilder().name(columnName)
.field(field).type(mappingType).id(id).udt(udt)
.reader(bean -> reflections.getValue(bean, field))
.writer((bean, value) -> reflections.setValue(bean, field, value));
if (nonNull(convert)) {
builder.converter(convert.value());
}
switch (mappingType) {
case COLLECTION, MAP -> {
builder.typeSupplier(field::getGenericType);
return builder.buildGeneric();
}
case EMBEDDED -> {
return builder.entityName(reflections.getEntityName(field.getType())).buildEmbedded();
}
default -> {
return builder.buildDefault();
}
}
}
}