1

I am facing trouble catching a NonUniqueResultException from a method of one of my beans.

Here is the method. It is inside of a @Stateful bean.

public Field findByTitle(String title) {
    if (title == null)
        return null;

    try {
        return entityManager
                .createQuery("SELECT f FROM Field f WHERE f.title = ?1", Field.class)
                .setParameter(1, title)
                .getSingleResult();
    } catch (NoResultException e) {
        return null;
    } 
}

Simply put, I want to catch the unchecked NonUniqueResultException from another bean which calls this method.

Here is the try/catch of the calling bean:

try {
    Field field = fieldService.findByTitle(title);
} catch (NonUniqueResultException e) {
    LogManager.logError("Oh no!");
}

My expectation is that "Oh no!" will be printed to the console. Instead, the entire stack trace of the NonUniqueResultException is printed. The catch call is never even touched!

Stack Trace: (Refers to this line: .getSingleResult();)

03:39:07,228 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (default task-93) javax.ejb.EJBException: javax.persistence.NonUniqueResultException: result returns more than one elements
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInterceptor.java:187)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:277)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:327)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:239)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:43)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:100)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:66)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356)
    at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:636)
    at org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:61)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356)
    at org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:195)
    at org.jboss.as.ee.component.ViewDescription$1.processInvocation(ViewDescription.java:185)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:73)
    at me.mitcht.myapp.core.entities.services.FieldService$$$view157.findByTitle(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:436)
    at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:127)
    at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56)
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:100)
    at me.mitcht.myapp.core.entities.services.FieldService$Proxy$_$$_Weld$EnterpriseProxy$.findByTitle(Unknown Source)
    at me.mitcht.myapp.web.validators.UniqueFieldValidator.validate(UniqueFieldValidator.java:39)
    at javax.faces.component.UIInput.validateValue(UIInput.java:1164)
    at javax.faces.component.UIInput.validate(UIInput.java:982)
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1248)
    at javax.faces.component.UIInput.processValidators(UIInput.java:712)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
    at javax.faces.component.UIForm.processValidators(UIForm.java:253)
    at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:575)
    at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1689)
    at javax.faces.component.UIForm.visitTree(UIForm.java:371)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
    at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:403)
    at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:266)
    at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:57)
    at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:219)
    at org.omnifaces.context.OmniPartialViewContext.processPartial(OmniPartialViewContext.java:144)
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1193)
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:81)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:265)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchToPath(ServletInitialHandler.java:200)
    at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:193)
    at io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:106)
    at me.mitcht.myapp.web.filters.TenantFilter.doFilter(TenantFilter.java:73)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:284)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:174)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:793)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: javax.persistence.NonUniqueResultException: result returns more than one elements
    at org.hibernate.jpa.internal.QueryImpl.getSingleResult(QueryImpl.java:539)
    at me.mitcht.myapp.core.entities.services.FieldService.findByTitle(FieldService.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.jboss.as.ee.component.ManagedReferenceMethodInterceptor.processInvocation(ManagedReferenceMethodInterceptor.java:52)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:437)
    at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.doMethodInterception(Jsr299BindingsInterceptor.java:82)
    at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.processInvocation(Jsr299BindingsInterceptor.java:93)
    at org.jboss.as.ee.component.interceptors.UserInterceptorFactory$1.processInvocation(UserInterceptorFactory.java:63)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.component.invocationmetrics.ExecutionTimeInterceptor.processInvocation(ExecutionTimeInterceptor.java:43)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.jpa.interceptor.SBInvocationInterceptor.processInvocation(SBInvocationInterceptor.java:47)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.jpa.interceptor.SFSBInvocationInterceptor.processInvocation(SFSBInvocationInterceptor.java:57)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.component.stateful.StatefulSessionSynchronizationInterceptor.processInvocation(StatefulSessionSynchronizationInterceptor.java:125)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:437)
    at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:64)
    at org.jboss.as.weld.ejb.EjbRequestScopeActivationInterceptor.processInvocation(EjbRequestScopeActivationInterceptor.java:83)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.invocation.InitialInterceptor.processInvocation(InitialInterceptor.java:21)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(ComponentDispatcherInterceptor.java:52)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.component.stateful.StatefulComponentInstanceInterceptor.processInvocation(StatefulComponentInstanceInterceptor.java:65)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:275)
    ... 112 more

What am I doing wrong?

Update: Tried throwing the cause again; same result.

public Field findByTitle(String title) {
    if (title == null)
        return null;

    try {
        return entityManager
                .createQuery("SELECT f FROM Field f WHERE f.title = ?1", Field.class)
                .setParameter(1, title)
                .getSingleResult();
    } catch (NoResultException e) {
        return null;
    } catch (NonUniqueResultException e) {
        throw e;
    }
}

Update: This is working. It's not how I'd like it to work though...

try {
    Field field = fieldService.findByTitle(title);
} catch (EJBException e) {
    if (e.getCause() instanceof NonUniqueResultException) {
        LogManager.logInfo("Oh no!");
    }
    return;
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Mitch Talmadge
  • 4,638
  • 3
  • 26
  • 44
  • Please provide a properly formatted stack trace (or relevant parts) that you encounter. I have an idea, but need to verify it by reading the stack trace. – MWiesner Jul 31 '16 at 09:56
  • @MWiesner Done. Let me know if you need the upper portion of the trace. I only included the "Caused by" section. – Mitch Talmadge Jul 31 '16 at 09:59
  • by the way: obviously, the method signature should be `public Collection findByTitle(String title)`. Would be logic to me, as the query you trigger here tends to return multiple results. Thus, this method should return a collection. (in case "title" does not have a unique constraint) – MWiesner Jul 31 '16 at 10:04
  • 1
    It's not the actual exception, which is thrown: `Caused by: javax.persistence.NonUniqueResultException: result returns more than one elements`. Pay attention to **Caused by** – Dmitry Ginzburg Jul 31 '16 at 10:04
  • @MWiesner Done again. Also, `getSingleResult` will only return one object. The point is that if there are more objects that match, the exception is thrown. – Mitch Talmadge Jul 31 '16 at 10:06
  • so you'd better use `getResultList()` then - try to change it, It'll resolve your problem the way it is natural for a query like that. – MWiesner Jul 31 '16 at 10:08
  • 1
    @DmitryGinzburg Oh... oops. I just noticed it says `javax.ejb.EJBException` at the top. That never even crossed my mind that `Caused by` would hint that a different exception is being thrown. Is there no way to get just the `NonUniqueResultException`? – Mitch Talmadge Jul 31 '16 at 10:08
  • See: always read the full stack trace and understand that first. – MWiesner Jul 31 '16 at 10:08
  • @MitchTalmadge catch it and rethrow the cause – Dmitry Ginzburg Jul 31 '16 at 10:08
  • @DmitryGinzburg I've already tried that. It has the same result. – Mitch Talmadge Jul 31 '16 at 10:09
  • @MitchTalmadge show us the code? You can update the question. – Dmitry Ginzburg Jul 31 '16 at 10:10
  • @DmitryGinzburg don't let him update his code, as it might change the sense of the original question/problem. – MWiesner Jul 31 '16 at 10:11
  • @MWiesner actually updates like "UPD: I tried blah-blah and I got blah-blah" are much better than something like this in comments. – Dmitry Ginzburg Jul 31 '16 at 10:12
  • @DmitryGinzburg Look at the bottom. Thanks for your help guys. – Mitch Talmadge Jul 31 '16 at 10:13
  • OK, now I can figure out an answer. – Dmitry Ginzburg Jul 31 '16 at 10:13
  • @MitchTalmadge Simply consider to change the method signature as proposed in one of my above comments and use `getResultList()`. It will avoid all these exception catching stuff... – MWiesner Jul 31 '16 at 10:15

4 Answers4

2

When called from a @Stateful annotated container managed bean, you'll receive an EJBException thus you'll need to catch that one (as reported in the answer of Dmitry Ginzburg).

However, a more consistent approach (solution) of the problem would be to change the method signature and the implementation as follows:

public List<Field> findByTitle(String title) {
    if (title == null)
        return null;

    try {
        TypedQuery<Field> query =  entityManager
                .createTypedQuery("SELECT f FROM Field f WHERE f.title = ?1", Field.class);
        query.setParameter(1, title)
        return query.getResultList();
    } catch (NoResultException e) {
        return null;
    } 
}

Provoking/Accepting exception handling is almost never a valid approach. Always go for properly designed interfaces that reflect the situation of what you are trying to achieve.

MWiesner
  • 8,868
  • 11
  • 36
  • 70
  • I appreciate yours and Dmitry's time spent helping me with this. Thanks so much!! – Mitch Talmadge Jul 31 '16 at 10:36
  • 1
    you're welcome. I'd like to add that Dmitry's way of solving it is not wrong per se. It depends on your requirements to the interface of that persistence service. Personally, I prefer good design over unnecessary glue code. – MWiesner Jul 31 '16 at 10:38
0

You can try to fix it by adding limit on the end of query.

public Field findByTitle(String title) {
    if (title == null)
        return null;

    try {
        return entityManager
                .createQuery("SELECT f FROM Field f WHERE f.title = ?1 LIMIT 1,1", Field.class)
                .setParameter(1, title)
                .getSingleResult();
    } catch (NoResultException e) {
        return null;
    }
}
Aleksandar Đokić
  • 2,118
  • 17
  • 35
  • 1
    Unfortunately JPQL does not support `LIMIT` within the query. However, adding `.setMaxResults(1)` does prevent the exception from being thrown if there are more than one rows that match within the database. I'd still like to know why this is not being caught though. – Mitch Talmadge Jul 31 '16 at 09:54
  • 1
    That's not a valid answer to the question, but a workaround to the problem. – MWiesner Jul 31 '16 at 09:56
0

The actual exception thrown is javax.ejb.EJBException, so you have to catch it and then rethrow the cause:

try {
    ....
} catch (EJBException ex) {
    if (ex.getCause() instanceof NonUniqueResultException) {
        throw (NonUniqueResultException)ex.getCause();
    }
}
Dmitry Ginzburg
  • 7,391
  • 2
  • 37
  • 48
  • won't work - it's glueing around the cause of the problem. – MWiesner Jul 31 '16 at 10:16
  • Actually, if the code is supposed to return only one value, then we should throw an exception if we find more than one value, so that's the way to go. – Dmitry Ginzburg Jul 31 '16 at 10:17
  • you are correct - as per se - however it is really bad design (thinking) to accept such glue code to patch a mis-designed persistence layer's interface. Obviously, his database allows more than one unique value for `title`. – MWiesner Jul 31 '16 at 10:19
  • Actually, the `EJBException` is being thrown outside of the bean, as it is a proxy. The`NonUniqueResultException` is thrown inside the method. On the outside, where I call the method, I am accessing the proxy, therefore I get an `EJBException`. So, if I catch `EJBException` where I am calling, then use the `getCause` as you are, it works like it should. I will update my post to reflect this. – Mitch Talmadge Jul 31 '16 at 10:21
  • @MitchTalmadge You are right. It's a container / layer related problem. Was trying to bring that to an answer by my own, however, you'll work that out ;) – MWiesner Jul 31 '16 at 10:22
  • @MWiesner I'll post it as an answer then. I will probably just use your solution since this isn't working how I'd like it to :P – Mitch Talmadge Jul 31 '16 at 10:25
  • @MWiesner Just to make sure I'm following what you're saying, please look at my answer and make sure I'm on the same page. Thanks! – Mitch Talmadge Jul 31 '16 at 10:31
0

As it turned out, because I am accessing the bean as a proxy, the actual exception being thrown is javax.ejb.EJBException. See this line from the stack trace:

javax.ejb.EJBException: javax.persistence.NonUniqueResultException: result returns more than one elements

So, the (ugly) solution is to catch the EJBException rather than NonUniqueResultException, and then check the cause to make sure it is what I expect:

try {
    Field field = fieldService.findByTitle(title);
} catch (EJBException e) {
    if (e.getCause() instanceof NonUniqueResultException) {
        LogManager.logInfo("Oh no!");
    }
    return;
}

This works, but looks terrible, and you can tell it's just bad design.

Therefore, I have chosen to use the suggested solution of MWiesner to return a Collection of the results rather than just one result. This way I can simply check the size of the collection. If it is larger than 1, obviously the results are not unique.

Community
  • 1
  • 1
Mitch Talmadge
  • 4,638
  • 3
  • 26
  • 44
  • Additional hint: if you want to (just) check the size, add another method in the persistence service interface, e.g. `int getFieldCount(String title)` and implement that with a native "SELECT count(...) ..." query to check whether more than one `Field` tuples exist for a given `title`. Reason: No object (data) will be fetched from the DB which is much better in terms of performance (especially if many instances of `Field` would be returned). – MWiesner Jul 31 '16 at 10:43
  • 1
    @MWiesner That's a great idea. Thank you again :) – Mitch Talmadge Jul 31 '16 at 10:44