use of io.micronaut.data.intercept.DataInterceptor in project micronaut-data by micronaut-projects.
the class UpdateMethodMatcher method entityUpdate.
private UpdateCriteriaMethodMatch entityUpdate(java.util.regex.Matcher matcher, ParameterElement entityParameter, ParameterElement entitiesParameter) {
return new UpdateCriteriaMethodMatch(matcher) {
ParameterElement entityParam = entityParameter == null ? entitiesParameter : entityParameter;
@Override
protected <T> void applyPredicates(List<ParameterElement> parameters, PersistentEntityRoot<T> root, PersistentEntityCriteriaUpdate<T> query, SourcePersistentEntityCriteriaBuilder cb) {
final SourcePersistentEntity rootEntity = (SourcePersistentEntity) root.getPersistentEntity();
Predicate predicate;
if (rootEntity.getVersion() != null) {
predicate = cb.and(cb.equal(root.id(), cb.entityPropertyParameter(entityParam)), cb.equal(root.version(), cb.entityPropertyParameter(entityParam)));
} else {
predicate = cb.equal(root.id(), cb.entityPropertyParameter(entityParam));
}
query.where(predicate);
}
@Override
protected <T> void addPropertiesToUpdate(MethodMatchContext matchContext, PersistentEntityRoot<T> root, PersistentEntityCriteriaUpdate<T> query, SourcePersistentEntityCriteriaBuilder cb) {
final SourcePersistentEntity rootEntity = matchContext.getRootEntity();
Stream.concat(rootEntity.getPersistentProperties().stream(), Stream.of(rootEntity.getVersion())).filter(p -> p != null && !((p instanceof Association) && ((Association) p).isForeignKey()) && !p.isGenerated() && p.findAnnotation(AutoPopulated.class).map(ap -> ap.getRequiredValue(AutoPopulated.UPDATEABLE, Boolean.class)).orElse(true)).forEach(p -> query.set(p.getName(), cb.entityPropertyParameter(entityParam)));
if (((AbstractPersistentEntityCriteriaUpdate<T>) query).getUpdateValues().isEmpty()) {
// Workaround for only ID entities
query.set(rootEntity.getIdentity().getName(), cb.entityPropertyParameter(entityParam));
}
}
@Override
protected boolean supportedByImplicitQueries() {
return true;
}
@Override
protected Map.Entry<ClassElement, Class<? extends DataInterceptor>> resolveReturnTypeAndInterceptor(MethodMatchContext matchContext) {
Map.Entry<ClassElement, Class<? extends DataInterceptor>> e = super.resolveReturnTypeAndInterceptor(matchContext);
ClassElement returnType = e.getKey();
if (returnType != null && !TypeUtils.isVoid(returnType) && !TypeUtils.isNumber(returnType) && !returnType.hasStereotype(MappedEntity.class) && !(TypeUtils.isReactiveOrFuture(matchContext.getReturnType()) && TypeUtils.isObjectClass(returnType))) {
throw new MatchFailedException("Cannot implement update method for specified return type: " + returnType.getName());
}
return e;
}
@Override
protected ParameterElement getEntityParameter() {
return entityParameter;
}
@Override
protected ParameterElement getEntitiesParameter() {
return entitiesParameter;
}
};
}
use of io.micronaut.data.intercept.DataInterceptor in project micronaut-data by micronaut-projects.
the class UpdateCriteriaMethodMatch method build.
@Override
protected MethodMatchInfo build(MethodMatchContext matchContext) {
MethodMatchSourcePersistentEntityCriteriaBuilderImpl cb = new MethodMatchSourcePersistentEntityCriteriaBuilderImpl(matchContext);
PersistentEntityCriteriaUpdate<Object> criteriaQuery = cb.createCriteriaUpdate(null);
apply(matchContext, criteriaQuery.from(matchContext.getRootEntity()), criteriaQuery, cb);
Map.Entry<ClassElement, Class<? extends DataInterceptor>> entry = resolveReturnTypeAndInterceptor(matchContext);
ClassElement resultType = entry.getKey();
Class<? extends DataInterceptor> interceptorType = entry.getValue();
AbstractPersistentEntityCriteriaUpdate<?> criteriaUpdate = (AbstractPersistentEntityCriteriaUpdate<?>) criteriaQuery;
boolean optimisticLock = criteriaUpdate.hasVersionRestriction();
final AnnotationMetadataHierarchy annotationMetadataHierarchy = new AnnotationMetadataHierarchy(matchContext.getRepositoryClass().getAnnotationMetadata(), matchContext.getAnnotationMetadata());
QueryBuilder queryBuilder = matchContext.getQueryBuilder();
Map<String, Object> propertiesToUpdate = criteriaUpdate.getUpdateValues();
QueryModel queryModel = ((AbstractPersistentEntityCriteriaUpdate) criteriaQuery).getQueryModel();
QueryResult queryResult = queryBuilder.buildUpdate(annotationMetadataHierarchy, queryModel, propertiesToUpdate);
return new MethodMatchInfo(DataMethod.OperationType.UPDATE, resultType, getInterceptorElement(matchContext, interceptorType)).optimisticLock(optimisticLock).queryResult(queryResult);
}
use of io.micronaut.data.intercept.DataInterceptor in project micronaut-data by micronaut-projects.
the class AbstractCriteriaMethodMatch method buildMatchInfo.
@Override
public final MethodMatchInfo buildMatchInfo(MethodMatchContext matchContext) {
MethodMatchInfo methodMatchInfo;
if (supportedByImplicitQueries() && matchContext.supportsImplicitQueries() && hasNoWhereAndJoinDeclaration(matchContext)) {
Map.Entry<ClassElement, Class<? extends DataInterceptor>> entry = resolveReturnTypeAndInterceptor(matchContext);
methodMatchInfo = new MethodMatchInfo(getOperationType(), entry.getKey(), getInterceptorElement(matchContext, entry.getValue()));
} else {
methodMatchInfo = build(matchContext);
}
ParameterElement entityParameter = getEntityParameter();
ParameterElement entitiesParameter = getEntitiesParameter();
ParameterElement idParameter = Arrays.stream(matchContext.getParameters()).filter(p -> p.hasAnnotation(Id.class)).findFirst().orElse(null);
if (idParameter != null) {
methodMatchInfo.addParameterRole(TypeRole.ID, idParameter.stringValue(Parameter.class).orElse(idParameter.getName()));
}
if (entityParameter != null) {
methodMatchInfo.encodeEntityParameters(true);
methodMatchInfo.addParameterRole(TypeRole.ENTITY, entityParameter.getName());
} else if (entitiesParameter != null) {
methodMatchInfo.encodeEntityParameters(true);
methodMatchInfo.addParameterRole(TypeRole.ENTITIES, entitiesParameter.getName());
}
return methodMatchInfo;
}
use of io.micronaut.data.intercept.DataInterceptor in project micronaut-data by micronaut-projects.
the class RawQueryMethodMatcher method match.
@Override
public MethodMatch match(MethodMatchContext matchContext) {
if (matchContext.getMethodElement().stringValue(Query.class).isPresent()) {
return new MethodMatch() {
@Override
public MethodMatchInfo buildMatchInfo(MethodMatchContext matchContext) {
MethodElement methodElement = matchContext.getMethodElement();
ParameterElement[] parameters = matchContext.getParameters();
ParameterElement entityParameter;
ParameterElement entitiesParameter;
if (parameters.length > 1) {
entityParameter = null;
entitiesParameter = null;
} else {
entityParameter = Arrays.stream(parameters).filter(p -> TypeUtils.isEntity(p.getGenericType())).findFirst().orElse(null);
entitiesParameter = Arrays.stream(parameters).filter(p -> TypeUtils.isIterableOfEntity(p.getGenericType())).findFirst().orElse(null);
}
boolean readOnly = matchContext.getAnnotationMetadata().booleanValue(Query.class, "readOnly").orElse(true);
String query = matchContext.getAnnotationMetadata().stringValue(Query.class).orElseThrow(IllegalStateException::new);
DataMethod.OperationType operationType = findOperationType(methodElement.getName(), query, readOnly);
Map.Entry<ClassElement, Class<? extends DataInterceptor>> entry = FindersUtils.resolveInterceptorTypeByOperationType(entityParameter != null, entitiesParameter != null, operationType, matchContext);
ClassElement resultType = entry.getKey();
Class<? extends DataInterceptor> interceptorType = entry.getValue();
if (interceptorType.getSimpleName().startsWith("SaveOne")) {
// Use `executeUpdate` operation for "insert(String a, String b)" style queries
// - custom query doesn't need to use root entity
// - we would like to know how many rows were updated
operationType = DataMethod.OperationType.UPDATE;
Map.Entry<ClassElement, Class<? extends DataInterceptor>> e = FindersUtils.pickUpdateInterceptor(matchContext, matchContext.getReturnType());
resultType = e.getKey();
interceptorType = e.getValue();
}
if (operationType == DataMethod.OperationType.QUERY) {
// Entity parameter/parameters only make sense if the operation is based on entity
entityParameter = null;
entitiesParameter = null;
}
boolean isDto = false;
if (resultType == null) {
resultType = matchContext.getRootEntity().getType();
} else {
if (operationType == DataMethod.OperationType.QUERY) {
if (resultType.hasAnnotation(Introspected.class)) {
if (!resultType.hasAnnotation(MappedEntity.class)) {
isDto = true;
}
}
} else if (!isValidReturnType(resultType, operationType)) {
throw new MatchFailedException("Invalid result type: " + resultType.getName() + " for '" + operationType + "' operation");
}
}
MethodMatchInfo methodMatchInfo = new MethodMatchInfo(operationType, resultType, FindersUtils.getInterceptorElement(matchContext, interceptorType));
methodMatchInfo.dto(isDto);
buildRawQuery(matchContext, methodMatchInfo, entityParameter, entitiesParameter, operationType);
if (entityParameter != null) {
methodMatchInfo.addParameterRole(TypeRole.ENTITY, entityParameter.getName());
} else if (entitiesParameter != null) {
methodMatchInfo.addParameterRole(TypeRole.ENTITIES, entitiesParameter.getName());
}
return methodMatchInfo;
}
};
}
return null;
}
use of io.micronaut.data.intercept.DataInterceptor in project micronaut-coherence by micronaut-projects.
the class CoherenceDataIntroductionAdvice method intercept.
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
RepositoryMethodKey key = new RepositoryMethodKey(context.getTarget(), context.getExecutableMethod());
DataInterceptor<Object, Object> dataInterceptor = interceptorMap.get(key);
if (dataInterceptor == null) {
String dataSourceName = context.stringValue(Repository.class).orElse(null);
Class<?> operationsType = context.classValue(RepositoryConfiguration.class, "operations").orElse(PrimaryRepositoryOperations.class);
Class<?> interceptorType = context.classValue(DataMethod.class, DataMethod.META_MEMBER_INTERCEPTOR).orElse(null);
if (interceptorType != null && DataInterceptor.class.isAssignableFrom(interceptorType)) {
DataInterceptor<Object, Object> childInterceptor = findInterceptor(dataSourceName, operationsType, interceptorType);
interceptorMap.put(key, childInterceptor);
return childInterceptor.intercept(key, context);
} else {
final AnnotationValue<DataMethod> declaredAnnotation = context.getDeclaredAnnotation(DataMethod.class);
if (declaredAnnotation != null) {
interceptorType = declaredAnnotation.classValue(DataMethod.META_MEMBER_INTERCEPTOR).orElse(null);
if (interceptorType != null && DataInterceptor.class.isAssignableFrom(interceptorType)) {
DataInterceptor<Object, Object> childInterceptor = findInterceptor(dataSourceName, operationsType, interceptorType);
interceptorMap.put(key, childInterceptor);
return childInterceptor.intercept(key, context);
}
}
final String interceptorName = context.getAnnotationMetadata().stringValue(DataMethod.class, DataMethod.META_MEMBER_INTERCEPTOR).orElse(null);
if (interceptorName != null) {
throw new IllegalStateException("Micronaut Data Interceptor [" + interceptorName + "] is not on" + " the classpath but required by the method: " + context.getExecutableMethod());
}
throw new IllegalStateException("Micronaut Data method is missing compilation time query " + "information. Ensure that the Micronaut Data annotation processors are declared in your" + " build and try again with a clean re-build.");
}
} else {
return dataInterceptor.intercept(key, context);
}
}
Aggregations