All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xlrit.gears.engine.importer.JpaImportTarget Maven / Gradle / Ivy

package com.xlrit.gears.engine.importer;

import java.util.*;

import com.google.common.base.Preconditions;
import com.xlrit.gears.engine.meta.*;
import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;

@RequiredArgsConstructor
public class JpaImportTarget extends ResolveDirectImportTarget {
	private final MetaManager metaManager;
	private final EntityManager entityManager;

	private EntityInfo currentEntity = null;

	@Override @SneakyThrows
	public void startCollection(String name) {
		super.startCollection(name);
		Class entityClass = Class.forName(name);
		currentEntity = metaManager.requireEntityInfo(entityClass);
	}

	@Override
	protected void doAdd(SkeletonObject skeleton) {
		Preconditions.checkState(currentEntity != null, "Tried to add object before starting collection");

		Object entity = currentEntity.newInstance(skeleton.id());
		for (var entry : skeleton.attributes().entrySet()) {
			SkeletonAttribute attribute = entry.getValue();
			if (attribute.isNull()) continue;
			BaseField field = currentEntity.getField(entry.getKey());
			if (field.isReadOnly()) continue;
			TypeInfo attributeType = field.getTypeInfo();
			if (attribute.isBasicValue()) {
				Object attrValue = buildSimpleValue(attributeType, attribute.getBasicValue());
				field.setValue(entity, attrValue);
			} // can safely assume direct references are either not present or other side already exists, since ResolveDirectImportTarget handles this
			else {
				Object attrValue = buildPointerValue(attributeType, attribute.getPointerValue());
				field.trySetValueBidi(entity, attrValue);
			}
		}
		entityManager.persist(entity);
	}

	private Object buildSimpleValue(TypeInfo attributeType, String rawValue) {
		if (!(attributeType instanceof BasicTypeInfo basicTypeInfo)) {
			throw new IllegalArgumentException("Cannot build simple value for attribute of type " + attributeType);
		}
		return rawValue == null ? null : basicTypeInfo.parse(rawValue);
	}

	@SneakyThrows
	private Object buildPointerValue(TypeInfo attributeType, List pointers) {
		if (attributeType instanceof EntityInfo) {
			if (pointers.size() != 1) {
				throw new IllegalArgumentException("Cannot build multiple pointers into one-to-X association");
			}
			Pointer pointer = pointers.getFirst();
			return requireReference(Class.forName(pointer.classFqn()), pointer.id());
		} else if (attributeType instanceof MultipleInfo multipleType) {
			if (!(multipleType.getElementType() instanceof EntityInfo)) {
				throw new IllegalArgumentException("Cannot build multiple attribute of type " + multipleType.getElementType());
			}
			List classes = pointers.stream().map(Pointer::classFqn).distinct().toList();
			if (classes.size() != 1) {
				throw new IllegalArgumentException("Cannot mix pointers to different types in multiple");
			}
			Class clazz = Class.forName(classes.getFirst());
			return pointers.stream()
					.map(ptr -> requireReference(clazz, ptr.id()))
					.toList();
		}
		throw new IllegalArgumentException("Cannot build pointer value for attribute of type " + attributeType);
	}

	private Object requireReference(Class clazz, String id) {
		Object object = entityManager.find(clazz, id);
		if (object == null) {
			throw new IllegalStateException(String.format("Tried to resolve reference to transient or non-existent object with id %s of class %s", id, clazz.getName()));
		}
		return object;
	}

	@Override
	public void endCollection() {
		entityManager.flush();
	}

	@Override
	public void close() {
		entityManager.close();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy