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

io.crnk.jpa.meta.internal.AbstractEntityMetaFactory Maven / Gradle / Ivy

There is a newer version: 2.6.20180522184741
Show newest version
package io.crnk.jpa.meta.internal;

import io.crnk.core.engine.internal.utils.ClassUtils;
import io.crnk.jpa.meta.MetaEntityAttribute;
import io.crnk.jpa.meta.MetaJpaDataObject;
import io.crnk.meta.model.MetaAttribute;
import io.crnk.meta.model.MetaDataObject;
import io.crnk.meta.model.MetaElement;
import io.crnk.meta.model.MetaPrimaryKey;

import javax.persistence.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;

public abstract class AbstractEntityMetaFactory extends AbstractJpaDataObjectFactory {

	@Override
	public MetaElement create(Type type) {
		Class rawClazz = ClassUtils.getRawType(type);
		Class superClazz = rawClazz.getSuperclass();
		MetaElement superMeta = getSuperMeta(superClazz);

		T meta = newDataObject();
		meta.setElementType(meta);
		meta.setName(rawClazz.getSimpleName());
		meta.setImplementationType(type);
		meta.setSuperType((MetaDataObject) superMeta);
		if (superMeta != null) {
			((MetaDataObject) superMeta).addSubType(meta);
		}
		createAttributes(meta);

		setKey(meta);

		return meta;
	}

	private MetaElement getSuperMeta(Class superClazz) {
		if (superClazz.getAnnotation(Entity.class) != null || superClazz.getAnnotation(MappedSuperclass.class) != null) {
			return context.allocate(superClazz);
		}
		return null;
	}

	private void setKey(T meta) {
		if (meta.getPrimaryKey() == null) {
			boolean generated = false;
			ArrayList pkElements = new ArrayList<>();
			for (MetaAttribute attr : meta.getAttributes()) {
				if (attr.getAnnotation(Id.class) != null || attr.getAnnotation(EmbeddedId.class) != null) {
					pkElements.add(attr);
					attr.setPrimaryKeyAttribute(true);

					boolean attrGenerated = attr.getAnnotation(GeneratedValue.class) != null;
					if (pkElements.size() == 1) {
						generated = attrGenerated;
					} else if (generated != attrGenerated) {
						throw new IllegalStateException(
								"cannot mix generated and not-generated primary key elements for " + meta.getId());
					}
				}
			}
			if (!pkElements.isEmpty()) {
				MetaPrimaryKey primaryKey = new MetaPrimaryKey();
				primaryKey.setName(meta.getName() + "$primaryKey");
				primaryKey.setElements(pkElements);
				primaryKey.setUnique(true);
				primaryKey.setParent(meta, true);
				primaryKey.setGenerated(generated);
				meta.setPrimaryKey(primaryKey);

				if (pkElements.size() == 1) {
					// single pk element cannot be nullable
					MetaAttribute pkElement = pkElements.get(0);
					pkElement.setNullable(false);
				}
			}
		}
	}

	protected abstract T newDataObject();

	@Override
	protected MetaAttribute createAttribute(T metaDataObject, String name) {
		MetaEntityAttribute attr = new MetaEntityAttribute();
		attr.setName(name);
		attr.setParent(metaDataObject, true);
		return attr;
	}

	@Override
	protected void initAttribute(MetaAttribute attr) {
		ManyToMany manyManyAnnotation = attr.getAnnotation(ManyToMany.class);
		ManyToOne manyOneAnnotation = attr.getAnnotation(ManyToOne.class);
		OneToMany oneManyAnnotation = attr.getAnnotation(OneToMany.class);
		OneToOne oneOneAnnotation = attr.getAnnotation(OneToOne.class);
		Version versionAnnotation = attr.getAnnotation(Version.class);
		Lob lobAnnotation = attr.getAnnotation(Lob.class);
		Column columnAnnotation = attr.getAnnotation(Column.class);

		boolean idAttr = attr.getAnnotation(Id.class) != null || attr.getAnnotation(EmbeddedId.class) != null;
		boolean attrGenerated = attr.getAnnotation(GeneratedValue.class) != null;

		attr.setVersion(versionAnnotation != null);
		attr.setAssociation(
				manyManyAnnotation != null || manyOneAnnotation != null || oneManyAnnotation != null || oneOneAnnotation !=
						null);

		attr.setLazy(isJpaLazy(attr.getAnnotations(), attr.isAssociation()));
		attr.setLob(lobAnnotation != null);
		attr.setFilterable(lobAnnotation == null);
		attr.setSortable(lobAnnotation == null);

		attr.setCascaded(getCascade(manyManyAnnotation, manyOneAnnotation, oneManyAnnotation, oneOneAnnotation));

		if (attr.getReadMethod() == null) {
			throw new IllegalStateException("no getter found for " + attr.getParent().getName() + "." + attr.getName());
		}
		Class attributeType = attr.getReadMethod().getReturnType();
		boolean isPrimitiveType = ClassUtils.isPrimitiveType(attributeType);
		boolean columnNullable = (columnAnnotation == null || columnAnnotation.nullable()) &&
				(manyOneAnnotation == null || manyOneAnnotation.optional()) &&
				(oneOneAnnotation == null || oneOneAnnotation.optional());
		attr.setNullable(!isPrimitiveType && columnNullable);

		boolean hasSetter = attr.getWriteMethod() != null;
		attr.setInsertable(hasSetter && (columnAnnotation == null || columnAnnotation.insertable()) && !attrGenerated
				&& versionAnnotation == null);
		attr.setUpdatable(
				hasSetter && (columnAnnotation == null || columnAnnotation.updatable()) && !idAttr && versionAnnotation == null);

	}

	protected boolean isJpaLazy(Collection annotations, boolean isAssociation) {
		for (Annotation annotation : annotations) {
			if (annotation instanceof OneToMany) {
				OneToMany oneToMany = (OneToMany) annotation;
				return oneToMany.fetch() == FetchType.LAZY;
			}
			if (annotation instanceof ManyToOne) {
				ManyToOne manyToOne = (ManyToOne) annotation;
				return manyToOne.fetch() == FetchType.LAZY;
			}
			if (annotation instanceof ManyToMany) {
				ManyToMany manyToMany = (ManyToMany) annotation;
				return manyToMany.fetch() == FetchType.LAZY;
			}
			if (annotation instanceof ElementCollection) {
				ElementCollection elementCollection = (ElementCollection) annotation;
				return elementCollection.fetch() == FetchType.LAZY;
			}
		}
		return isAssociation;
	}


	private boolean getCascade(ManyToMany manyManyAnnotation, ManyToOne manyOneAnnotation, OneToMany oneManyAnnotation,
							   OneToOne oneOneAnnotation) {
		if (manyManyAnnotation != null) {
			return getCascade(manyManyAnnotation.cascade());
		}
		if (manyOneAnnotation != null) {
			return getCascade(manyOneAnnotation.cascade());
		}
		if (oneManyAnnotation != null) {
			return getCascade(oneManyAnnotation.cascade());
		}
		if (oneOneAnnotation != null) {
			return getCascade(oneOneAnnotation.cascade());
		}
		return false;
	}

	private boolean getCascade(CascadeType[] types) {
		return types.length > 0;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy