Repository: deltaspike Updated Branches: refs/heads/master 70299c16d -> b722b8f47
DELTASPIKE-1036 Support for returning optional when object should be a single result type. Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/b722b8f4 Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/b722b8f4 Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/b722b8f4 Branch: refs/heads/master Commit: b722b8f47114390359b110169630cf9045fbad45 Parents: 70299c1 Author: John D. Ament <[email protected]> Authored: Thu Jun 2 21:44:25 2016 -0400 Committer: John D. Ament <[email protected]> Committed: Thu Jun 2 21:44:25 2016 -0400 ---------------------------------------------------------------------- .../deltaspike/core/util/OptionalUtil.java | 77 ++++++++++++++++++++ .../deltaspike/core/util/OptionalUtilTest.java | 65 +++++++++++++++++ .../builder/result/QueryProcessorFactory.java | 16 +++- .../impl/handler/CdiQueryInvocationContext.java | 15 +++- .../data/impl/meta/RepositoryMethod.java | 7 ++ .../deltaspike/data/impl/QueryResultTest.java | 14 ++++ .../data/test/service/SimpleRepository.java | 3 + 7 files changed, 193 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b722b8f4/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/OptionalUtil.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/OptionalUtil.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/OptionalUtil.java new file mode 100644 index 0000000..9782bf7 --- /dev/null +++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/OptionalUtil.java @@ -0,0 +1,77 @@ +/* + * 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.core.util; + +import javax.enterprise.inject.Typed; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +@Typed() +public abstract class OptionalUtil +{ + private static boolean optionalSupported = true; + private static Class<?> optionalClass; + private static Method optionalMethod; + + static { + try + { + optionalClass = Class.forName("java.util.Optional"); + optionalMethod = optionalClass.getMethod("ofNullable", Object.class); + } + catch (Exception e) + { + optionalSupported = false; + optionalClass = null; + optionalMethod = null; + } + } + + public static boolean isOptionalSupported() + { + return optionalSupported; + } + + public static boolean isOptionalReturned(Method method) + { + return optionalSupported && method.getReturnType().isAssignableFrom(optionalClass); + } + + public static Object wrap(Object input) + { + if (!optionalSupported) + { + return input; + } + try + { + return optionalMethod.invoke(null, input); + } + catch (IllegalAccessException e) + { + e.printStackTrace(); + } + catch (InvocationTargetException e) + { + e.printStackTrace(); + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b722b8f4/deltaspike/core/api/src/test/java/org/apache/deltaspike/core/util/OptionalUtilTest.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/api/src/test/java/org/apache/deltaspike/core/util/OptionalUtilTest.java b/deltaspike/core/api/src/test/java/org/apache/deltaspike/core/util/OptionalUtilTest.java new file mode 100644 index 0000000..7c76d9b --- /dev/null +++ b/deltaspike/core/api/src/test/java/org/apache/deltaspike/core/util/OptionalUtilTest.java @@ -0,0 +1,65 @@ +/* + * 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.core.util; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Method; + +public class OptionalUtilTest +{ + @Before + public void isEnabled() + { + Assume.assumeTrue(OptionalUtil.isOptionalSupported()); + } + + @Test + public void shouldIdentifyOptionalReturnType() throws Exception + { + Method empty = getOptionalClass().getMethod("empty"); + Assert.assertTrue(OptionalUtil.isOptionalReturned(empty)); + } + + @Test + public void shouldReturnEmptyWhenGivenNull() throws Exception + { + Object wrapped = OptionalUtil.wrap(null); + Method isPresent = getOptionalClass().getMethod("isPresent"); + Object invoke = isPresent.invoke(wrapped); + Assert.assertEquals(invoke, Boolean.FALSE); + } + + @Test + public void shouldReturnNotEmptyWhenGivenNonnull() throws Exception + { + Object wrapped = OptionalUtil.wrap("String"); + Method isPresent = getOptionalClass().getMethod("isPresent"); + Object invoke = isPresent.invoke(wrapped); + Assert.assertEquals(invoke, Boolean.TRUE); + } + + private static Class<?> getOptionalClass() throws ClassNotFoundException { + return Class.forName("java.util.Optional"); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b722b8f4/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessorFactory.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessorFactory.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessorFactory.java index 10052f1..470cbfe 100644 --- a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessorFactory.java +++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessorFactory.java @@ -24,6 +24,7 @@ import java.util.List; import javax.persistence.NoResultException; import javax.persistence.Query; +import org.apache.deltaspike.core.util.OptionalUtil; import org.apache.deltaspike.data.api.Modifying; import org.apache.deltaspike.data.api.QueryResult; import org.apache.deltaspike.data.api.SingleResultType; @@ -112,6 +113,7 @@ public final class QueryProcessorFactory public Object executeQuery(Query query, CdiQueryInvocationContext context) { SingleResultType style = context.getSingleResultStyle(); + Object result = null; switch (style) { case JPA: @@ -119,16 +121,24 @@ public final class QueryProcessorFactory case OPTIONAL: try { - return query.getSingleResult(); + result = query.getSingleResult(); } catch (NoResultException e) { - return null; } + break; default: @SuppressWarnings("unchecked") List<Object> queryResult = query.getResultList(); - return queryResult.size() > 0 ? queryResult.get(0) : null; + result = queryResult.size() > 0 ? queryResult.get(0) : null; + } + if (context.isOptional()) + { + return OptionalUtil.wrap(result); + } + else + { + return result; } } } http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b722b8f4/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java index 9f032e5..1adee68 100644 --- a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java +++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java @@ -278,7 +278,15 @@ public class CdiQueryInvocationContext implements QueryInvocationContext public SingleResultType getSingleResultStyle() { - return repoMethod.getSingleResultStyle(); + SingleResultType baseSingleResultType = repoMethod.getSingleResultStyle(); + if (repoMethod.isOptional() && baseSingleResultType == SingleResultType.JPA) + { + return SingleResultType.OPTIONAL; + } + else + { + return baseSingleResultType; + } } public Object getProxy() @@ -347,4 +355,9 @@ public class CdiQueryInvocationContext implements QueryInvocationContext } return false; } + + public boolean isOptional() + { + return this.repoMethod.isOptional(); + } } http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b722b8f4/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java index 08cedd8..e349e56 100644 --- a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java +++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java @@ -32,6 +32,7 @@ import javax.persistence.LockModeType; import org.apache.deltaspike.core.api.provider.BeanManagerProvider; import org.apache.deltaspike.core.api.provider.BeanProvider; import org.apache.deltaspike.core.api.provider.DependentProvider; +import org.apache.deltaspike.core.util.OptionalUtil; import org.apache.deltaspike.data.api.Modifying; import org.apache.deltaspike.data.api.Query; import org.apache.deltaspike.data.api.SingleResultType; @@ -63,6 +64,7 @@ public class RepositoryMethod private final QueryRoot queryRoot; private final QueryProcessor queryProcessor; private final Class<? extends QueryInOutMapper<?>> mapper; + private final boolean isOptional; private volatile Boolean queryInOutMapperIsNormalScope; @@ -75,6 +77,7 @@ public class RepositoryMethod this.queryRoot = initQueryRoot(); this.queryProcessor = QueryProcessorFactory.newInstance(method, methodPrefix).build(); this.mapper = extractMapper(method, repo); + this.isOptional = OptionalUtil.isOptionalReturned(this.method); } public boolean returns(Class<?> returnType) @@ -247,4 +250,8 @@ public class RepositoryMethod return hasLockMode || method.isAnnotationPresent(Modifying.class); } + public boolean isOptional() + { + return this.isOptional; + } } http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b722b8f4/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/QueryResultTest.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/QueryResultTest.java b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/QueryResultTest.java index a42025a..b40b710 100644 --- a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/QueryResultTest.java +++ b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/QueryResultTest.java @@ -398,6 +398,20 @@ public class QueryResultTest extends TransactionalTestCase // no real check here, verifying query syntax passes. assertNotNull(result); } +// TODO Figure out a way to test this that doesn't require java 8 +// @Test +// public void shouldFindbyIdOptional() +// { +// Simple simple = builder.createSimple("bob"); +// +// java.util.Optional<Simple> optional = repo.findById(simple.getId()); +// assertTrue(optional.isPresent()); +// +// long nextId = simple.getId() + 1; +// +// repo.findById(nextId); +// assertFalse(optional.isPresent()); +// } @Before public void setup() http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b722b8f4/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java index 977736d..7d2870f 100755 --- a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java +++ b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java @@ -121,6 +121,9 @@ public abstract class SimpleRepository extends AbstractEntityRepository<Simple, public abstract void removeByNameAndEnabled(String name, Boolean aTrue); +// TODO Figure out a way to test this that doesn't require java 8 +// public abstract java.util.Optional<Simple> findById(Long id); + @Override protected abstract EntityManager entityManager(); }
