io.micronaut.data.model.PersistentEntity Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of micronaut-data-model Show documentation
Show all versions of micronaut-data-model Show documentation
Data Repository Support for Micronaut
The newest version!
/*
* Copyright 2017-2020 original 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.micronaut.data.model;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.beans.BeanIntrospection;
import io.micronaut.core.naming.NameUtils;
import io.micronaut.core.util.ArgumentUtils;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.data.annotation.Embeddable;
import io.micronaut.data.model.naming.NamingStrategy;
import io.micronaut.data.model.runtime.RuntimePersistentEntity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import static io.micronaut.data.model.AssociationUtils.CAMEL_CASE_SPLIT_PATTERN;
/**
* Models a persistent entity and provides an API that can be used both within the compiler and at runtime. The {@link io.micronaut.core.annotation.AnnotationMetadata} provided is consistent both at runtime and compilation time.
*
* @see PersistentProperty
* @author Graeme Rocher
* @since 1.0
*/
public interface PersistentEntity extends PersistentElement {
/**
* The entity name including any package prefix.
*
* @return The entity name
*/
@Override
@NonNull String getName();
/**
* @return A name to use when referring to this element via an alias.
*/
@NonNull
String getAliasName();
/**
* Has composite identity.
*
* @return The true if composite identity present
*/
default boolean hasCompositeIdentity() {
return getCompositeIdentity() != null;
}
/**
* Has identity.
*
* @return The true if identity present
*/
default boolean hasIdentity() {
return getIdentity() != null;
}
/**
* The composite id.
*
* @return The composite id or null if there isn't one
*/
@Nullable PersistentProperty[] getCompositeIdentity();
/**
* Returns the identity of the instance.
*
* @return The identity or null if there isn't one
*/
@Nullable PersistentProperty getIdentity();
/**
* Returns all identity properties.
*
* @return The identity properties
*/
@NonNull
default List getIdentityProperties() {
if (getIdentity() != null) {
return List.of(getIdentity());
} else {
PersistentProperty[] compositeIdentity = getCompositeIdentity();
if (compositeIdentity != null) {
return List.of(compositeIdentity);
}
}
return List.of();
}
/**
* Returns the version property.
*
* @return the property
*/
@Nullable PersistentProperty getVersion();
/**
* Is the entity versioned for optimistic locking.
*
* @return true if versioned
*/
default boolean isVersioned() {
return getVersion() != null;
}
/**
* A list of properties to be persisted.
* @return A list of PersistentProperty instances
*/
@NonNull Collection extends PersistentProperty> getPersistentProperties();
/**
* A list of the associations for this entity. This is typically
* a subset of the list returned by {@link #getPersistentProperties()}
*
* @return A list of associations
*/
@NonNull
default Collection extends Association> getAssociations() {
return getPersistentProperties()
.stream()
.filter(bp -> bp instanceof Association)
.map(bp -> (Association) bp)
.toList();
}
/**
* A list of embedded associations for this entity. This is typically
* a subset of the list returned by {@link #getPersistentProperties()}
*
* @return A list of associations
*/
default @NonNull Collection getEmbedded() {
return getPersistentProperties().stream()
.filter(PersistentProperty::isEmbedded)
.map(p -> (Embedded) p)
.toList();
}
/**
* Obtains a PersistentProperty instance by name.
*
* @param name The name of the property
* @return The PersistentProperty or null if it doesn't exist
*/
@Nullable PersistentProperty getPropertyByName(String name);
/**
* Obtains an identity PersistentProperty instance by name.
*
* @param name The name of the identity property
* @return The PersistentProperty or null if it doesn't exist
*/
default @Nullable PersistentProperty getIdentityByName(String name) {
PersistentProperty identity = getIdentity();
if (identity != null && identity.getName().equals(name)) {
return identity;
}
PersistentProperty[] compositeIdentities = getCompositeIdentity();
if (compositeIdentities != null) {
for (PersistentProperty compositeIdentity : compositeIdentities) {
if (compositeIdentity.getName().equals(name)) {
return compositeIdentity;
}
}
}
return null;
}
/**
* A list of property names that a persistent.
* @return A List of strings
*/
@NonNull Collection getPersistentPropertyNames();
/**
* @return Is the entity embeddable.
*/
default boolean isEmbeddable() {
return getAnnotationMetadata().hasAnnotation(Embeddable.class);
}
/**
* @return The simple name without the package of entity
*/
@NonNull
default String getSimpleName() {
return NameUtils.getSimpleName(getName());
}
/**
* @return Returns the name of the class decapitalized form
*/
default @NonNull String getDecapitalizedName() {
return NameUtils.decapitalize(getSimpleName());
}
/**
* Returns whether the specified entity asserts ownership over this
* entity.
*
* @param owner The owning entity
* @return True if it does own this entity
*/
boolean isOwningEntity(PersistentEntity owner);
/**
* Returns the parent entity of this entity.
* @return The ParentEntity instance
*/
@Nullable PersistentEntity getParentEntity();
/**
* Computes a dot separated property path for the given camel case path.
* @param camelCasePath The camel case path
* @return The dot separated version or null if it cannot be computed
*/
default Optional getPath(String camelCasePath) {
List path = Arrays.stream(CAMEL_CASE_SPLIT_PATTERN.split(camelCasePath))
.map(NameUtils::decapitalize)
.toList();
if (CollectionUtils.isNotEmpty(path)) {
Iterator i = path.iterator();
StringBuilder b = new StringBuilder();
PersistentEntity currentEntity = this;
String name = null;
while (i.hasNext()) {
name = name == null ? i.next() : name + NameUtils.capitalize(i.next());
PersistentProperty sp = currentEntity.getPropertyByName(name);
if (sp == null) {
PersistentProperty identity = currentEntity.getIdentity();
if (identity != null) {
if (identity.getName().equals(name)) {
sp = identity;
} else if (identity instanceof Association association) {
PersistentEntity idEntity = association.getAssociatedEntity();
sp = idEntity.getPropertyByName(name);
}
}
}
if (sp != null) {
if (sp instanceof Association association) {
b.append(name);
if (i.hasNext()) {
b.append('.');
}
currentEntity = association.getAssociatedEntity();
name = null;
} else if (!i.hasNext()) {
b.append(name);
}
}
}
return b.isEmpty() || b.charAt(b.length() - 1) == '.' ? Optional.empty() : Optional.of(b.toString());
}
return Optional.empty();
}
/**
* Obtains the root entity of an inheritance hierarchy.
* @return The root entity
*/
default @NonNull PersistentEntity getRootEntity() {
return this;
}
/**
* Whether this entity is a root entity.
* @return True if it is a root entity
*/
default boolean isRoot() {
return getRootEntity() == this;
}
/**
* Return a property for a dot separated property path such as {@code foo.bar.prop}
* .
* @param path The path
* @return The property
*/
default Optional getPropertyByPath(String path) {
if (path.indexOf('.') == -1) {
PersistentProperty pp = getPropertyByName(path);
if (pp == null) {
PersistentProperty identity = getIdentity();
if (identity != null) {
if (identity.getName().equals(path)) {
pp = identity;
} else if (identity instanceof Embedded embedded) {
PersistentEntity idEntity = embedded.getAssociatedEntity();
pp = idEntity.getPropertyByName(path);
}
}
}
return Optional.ofNullable(pp);
} else {
String[] tokens = path.split("\\.");
PersistentEntity startingEntity = this;
PersistentProperty prop = null;
for (String token : tokens) {
prop = startingEntity.getPropertyByName(token);
if (prop == null) {
PersistentProperty identity = startingEntity.getIdentity();
if (identity != null && identity.getName().equals(token)) {
prop = identity;
} else {
return Optional.empty();
}
}
if (prop instanceof Association association) {
startingEntity = association.getAssociatedEntity();
}
}
return Optional.ofNullable(prop);
}
}
/**
* Return a {@link PersistentPropertyPath} by path such as {@code foo.bar.prop}.
* .
* @param path The path
* @return The properties
*/
@Nullable
default PersistentPropertyPath getPropertyPath(@NonNull String path) {
if (path.indexOf('.') == -1) {
return getPropertyPath(new String[] {path});
}
return getPropertyPath(StringUtils.splitOmitEmptyStringsList(path, '.').toArray(new String[0]));
}
/**
* Return a {@link PersistentPropertyPath} by path such as {@code foo.bar.prop}.
* .
* @param propertyPath The path
* @return The properties
*/
@Nullable
default PersistentPropertyPath getPropertyPath(@NonNull String[] propertyPath) {
if (propertyPath.length == 0) {
return null;
}
if (propertyPath.length == 1) {
String propertyName = propertyPath[0];
PersistentProperty pp = getPropertyByName(propertyName);
if (pp == null) {
PersistentProperty identity = getIdentity();
if (identity != null) {
if (identity.getName().equals(propertyName)) {
pp = identity;
} else if (identity instanceof Embedded embedded) {
PersistentEntity idEntity = embedded.getAssociatedEntity();
pp = idEntity.getPropertyByName(propertyName);
if (pp != null) {
return PersistentPropertyPath.of(Collections.singletonList((Embedded) identity), pp, identity.getName() + "." + pp.getName());
}
}
}
PersistentProperty version = getVersion();
if (version != null) {
if (version.getName().equals(propertyName)) {
pp = version;
}
}
}
return pp == null ? null : PersistentPropertyPath.of(Collections.emptyList(), pp, propertyName);
} else {
List associations = new ArrayList<>(propertyPath.length - 1);
PersistentEntity startingEntity = this;
for (int i = 0; i < propertyPath.length - 1; i++) {
String propertyName = propertyPath[i];
PersistentProperty prop = startingEntity.getPropertyByName(propertyName);
if (prop instanceof Association association) {
startingEntity = association.getAssociatedEntity();
associations.add(association);
} else {
if (prop == null) {
return null;
}
throw new IllegalArgumentException("Invalid association path. Property [" + propertyName + "] of [" + startingEntity + "] is not an association in [" + String.join(".", propertyPath) + "]");
}
}
PersistentProperty prop = startingEntity.getPropertyByName(propertyPath[propertyPath.length - 1]);
if (prop == null) {
return null;
}
return PersistentPropertyPath.of(associations, prop);
}
}
/**
* Obtain the naming strategy for the entity.
* @return The naming strategy
*/
@NonNull
NamingStrategy getNamingStrategy();
/**
* Find the naming strategy that is defined for the entity.
* @return The optional naming strategy
*/
@NonNull
Optional findNamingStrategy();
/**
* Creates a new persistent entity representation of the given type. The type
* must be annotated with {@link io.micronaut.core.annotation.Introspected}. This method will create a new instance on demand and does not cache.
*
* @param type The type
* @param The generic type
* @return The entity
*/
static @NonNull RuntimePersistentEntity of(@NonNull Class type) {
ArgumentUtils.requireNonNull("type", type);
return new RuntimePersistentEntity<>(type);
}
/**
* Creates a new persistent entity representation of the given type. The type
* must be annotated with {@link io.micronaut.core.annotation.Introspected}. This method will create a new instance on demand and does not cache.
*
* @param introspection The introspection
* @param The generic type
* @return The entity
*/
static @NonNull RuntimePersistentEntity of(@NonNull BeanIntrospection introspection) {
ArgumentUtils.requireNonNull("introspection", introspection);
return new RuntimePersistentEntity<>(introspection);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy