/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 * * http://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 org.apache.deltaspike.data.impl.builder.result; import java.lang.reflect.Method; import java.util.List; import javax.persistence.NoResultException; import javax.persistence.Query; import org.apache.deltaspike.core.util.OptionalUtil; import org.apache.deltaspike.core.util.StreamUtil; import org.apache.deltaspike.data.api.Modifying; import org.apache.deltaspike.data.api.QueryResult; import org.apache.deltaspike.data.api.SingleResultType; import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext; import org.apache.deltaspike.data.impl.meta.MethodPrefix; public final class QueryProcessorFactory { private final Method method; private final MethodPrefix methodPrefix; private QueryProcessorFactory(Method method) { this.method = method; this.methodPrefix = new MethodPrefix("", method.getName()); } private QueryProcessorFactory(Method method, MethodPrefix methodPrefix) { this.method = method; this.methodPrefix = methodPrefix; } public static QueryProcessorFactory newInstance(Method method) { return new QueryProcessorFactory(method); } public static QueryProcessorFactory newInstance(Method method, MethodPrefix methodPrefix) { return new QueryProcessorFactory(method, methodPrefix); } public QueryProcessor build() { if (returns(QueryResult.class)) { return new NoOpQueryProcessor(); } if (returns(List.class)) { return new ListQueryProcessor(); } if (streams()) { return new StreamQueryProcessor(); } if (isModifying()) { return new ExecuteUpdateQueryProcessor(returns(Void.TYPE)); } return new SingleResultQueryProcessor(); } private boolean isModifying() { boolean matchesType = Void.TYPE.equals(method.getReturnType()) || int.class.equals(method.getReturnType()) || Integer.class.equals(method.getReturnType()); return (method.isAnnotationPresent(Modifying.class) && matchesType) || methodPrefix.isDelete(); } private boolean returns(Class<?> clazz) { return method.getReturnType().isAssignableFrom(clazz); } private boolean streams() { return StreamUtil.isStreamReturned(method); } private static final class ListQueryProcessor implements QueryProcessor { @Override public Object executeQuery(Query query, CdiQueryInvocationContext context) { return query.getResultList(); } } private static final class NoOpQueryProcessor implements QueryProcessor { @Override public Object executeQuery(Query query, CdiQueryInvocationContext context) { return query; } } private static final class StreamQueryProcessor implements QueryProcessor { @Override public Object executeQuery(Query query, CdiQueryInvocationContext context) { return StreamUtil.wrap(query.getResultList()); } } private static final class SingleResultQueryProcessor implements QueryProcessor { @Override public Object executeQuery(Query query, CdiQueryInvocationContext context) { SingleResultType style = context.getSingleResultStyle(); Object result = null; switch (style) { case JPA: return query.getSingleResult(); case OPTIONAL: try { result = query.getSingleResult(); } catch (NoResultException e) { } break; default: @SuppressWarnings("unchecked") List<Object> queryResult = query.getResultList(); result = !queryResult.isEmpty() ? queryResult.get(0) : null; } if (context.isOptional()) { return OptionalUtil.wrap(result); } else { return result; } } } private static final class ExecuteUpdateQueryProcessor implements QueryProcessor { private final boolean returnsVoid; private ExecuteUpdateQueryProcessor(boolean returnsVoid) { this.returnsVoid = returnsVoid; } @Override public Object executeQuery(Query query, CdiQueryInvocationContext context) { int result = query.executeUpdate(); if (!returnsVoid) { return result; } return null; } } }