I have an insertOrUpdate method which inserts an Entity when it doesn't exist or update it if it does. To enable this, I have to findByIdAndForeignKey, if it returned null insert if not then update. The problem is how do I check if it exists? So I tried getSingleResult. But it throws an exception if the
public Profile findByUserNameAndPropertyName(String userName, String propertyName) {
String namedQuery = Profile.class.getSimpleName() + ".findByUserNameAndPropertyName";
Query query = entityManager.createNamedQuery(namedQuery);
query.setParameter("name", userName);
query.setParameter("propName", propertyName);
Object result = query.getSingleResult();
if (result == null) return null;
return (Profile) result;
}
but getSingleResult throws an Exception.
Thanks
Throwing an exception is how getSingleResult() indicates it can't be found. Personally I can't stand this kind of API. It forces spurious exception handling for no real benefit. You just have to wrap the code in a try-catch block.
Alternatively you can query for a list and see if its empty. That doesn't throw an exception. Actually since you're not doing a primary key lookup technically there could be multiple results (even if one, both or the combination of your foreign keys or constraints makes this impossible in practice) so this is probably the more appropriate solution.
Try this in Java 8:
Optional first = query.getResultList().stream().findFirst();
I encapsulated the logic in the following helper method.
public class JpaResultHelper {
public static Object getSingleResultOrNull(Query query){
List results = query.getResultList();
if (results.isEmpty()) return null;
else if (results.size() == 1) return results.get(0);
throw new NonUniqueResultException();
}
}
Here's a good option for doing this:
public static <T> T getSingleResult(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
I've done (in Java 8):
query.getResultList().stream().findFirst().orElse(null);
From JPA 2.2, instead of .getResultList() and checking if list is empty or creating a stream you can return stream and take first element.
.getResultStream()
.findFirst()
.orElse(null);
Spring has a utility method for this:
TypedQuery<Profile> query = em.createNamedQuery(namedQuery, Profile.class);
...
return org.springframework.dao.support.DataAccessUtils.singleResult(query.getResultList());
If you wish to use the try/catch mechanism to handle this problem.. then it can be used to act like if/else. I used the try/catch to add a new record when I didn't find an existing one.
try { //if part
record = query.getSingleResult();
//use the record from the fetched result.
}
catch(NoResultException e){ //else part
//create a new record.
record = new Record();
//.........
entityManager.persist(record);
}
Here's a typed/generics version, based on Rodrigo IronMan's implementation:
public static <T> T getSingleResultOrNull(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
There is an alternative which I would recommend:
Query query = em.createQuery("your query");
List<Element> elementList = query.getResultList();
return CollectionUtils.isEmpty(elementList ) ? null : elementList.get(0);
This safeguards against Null Pointer Exception, guarantees only 1 result is returned.
So don't do that!
You have two options:
Run a selection to obtain the COUNT of your result set, and only pull in the data if this count is non-zero; or
Use the other kind of query (that gets a result set) and check if it has 0 or more results. It should have 1, so pull that out of your result collection and you're done.
I'd go with the second suggestion, in agreement with Cletus. It gives better performance than (potentially) 2 queries. Also less work.
Combining the useful bits of the existing answers (limiting the number of results, checking that the result is unique) and using the estabilshed method name (Hibernate), we get:
/**
* Return a single instance that matches the query, or null if the query returns no results.
*
* #param query query (required)
* #param <T> result record type
* #return record or null
*/
public static <T> T uniqueResult(#NotNull TypedQuery<T> query) {
List<T> results = query.setMaxResults(2).getResultList();
if (results.size() > 1) throw new NonUniqueResultException();
return results.isEmpty() ? null : results.get(0);
}
The undocumented method uniqueResultOptional in org.hibernate.query.Query should do the trick. Instead of having to catch a NoResultException you can just call query.uniqueResultOptional().orElse(null).
I solved this by using List<?> myList = query.getResultList(); and checking if myList.size() equals to zero.
Look this code :
return query.getResultList().stream().findFirst().orElse(null);
When findFirst() is called maybe can be throwed a NullPointerException.
the best aproach is:
return query.getResultList().stream().filter(Objects::nonNull).findFirst().orElse(null);
Here's the same logic as others suggested (get the resultList, return its only element or null), using Google Guava and a TypedQuery.
public static <T> getSingleResultOrNull(final TypedQuery<T> query) {
return Iterables.getOnlyElement(query.getResultList(), null);
}
Note that Guava will return the unintuitive IllegalArgumentException if the result set has more than one result. (The exception makes sense to clients of getOnlyElement(), as it takes the result list as its argument, but is less understandable to clients of getSingleResultOrNull().)
Here's another extension, this time in Scala.
customerQuery.getSingleOrNone match {
case Some(c) => // ...
case None => // ...
}
With this pimp:
import javax.persistence.{NonUniqueResultException, TypedQuery}
import scala.collection.JavaConversions._
object Implicits {
class RichTypedQuery[T](q: TypedQuery[T]) {
def getSingleOrNone : Option[T] = {
val results = q.setMaxResults(2).getResultList
if (results.isEmpty)
None
else if (results.size == 1)
Some(results.head)
else
throw new NonUniqueResultException()
}
}
implicit def query2RichQuery[T](q: TypedQuery[T]) = new RichTypedQuery[T](q)
}
So all of the "try to rewrite without an exception" solution in this page has a minor problem. Either its not throwing NonUnique exception, nor throw it in some wrong cases too (see below).
I think the proper solution is (maybe) this:
public static <L> L getSingleResultOrNull(TypedQuery<L> query) {
List<L> results = query.getResultList();
L foundEntity = null;
if(!results.isEmpty()) {
foundEntity = results.get(0);
}
if(results.size() > 1) {
for(L result : results) {
if(result != foundEntity) {
throw new NonUniqueResultException();
}
}
}
return foundEntity;
}
Its returning with null if there is 0 element in the list, returning nonunique if there are different elements in the list, but not returning nonunique when one of your select is not properly designed and returns the same object more then one times.
Feel free to comment.
I achieved this by getting a result list then checking if it is empty
public boolean exist(String value) {
List<Object> options = getEntityManager().createNamedQuery("AppUsers.findByEmail").setParameter('email', value).getResultList();
return !options.isEmpty();
}
It is so annoying that getSingleResult() throws exceptions
Throws:
NoResultException - if there is no result
NonUniqueResultException - if more than one result
and some other exception that you can get more info on from their documentation
I prefer #Serafins answer if you can use the new JPA features, but this is one fairly straight forward way to do it which I'm surprised hasn't been mentioned here before:
try {
return (Profile) query.getSingleResult();
} catch (NoResultException ignore) {
return null;
}
`public Example validate(String param1) {
// TODO Auto-generated method stub
Example example = new Example();
Query query =null;
Object[] myResult =null;
try {
query = sessionFactory.getCurrentSession()
.createQuery("select column from table where
column=:p_param1");
query.setParameter("p_param1",param1);
}
myResult = (Object[])query.getSingleResult();//As your problem occurs here where the query has no records it is throwing an exception
String obj1 = (String) myResult[0];
String obj2 = (String) myResult[1];
example.setobj1(ISSUtil.convertNullToSpace(obj1))
example.setobj2(ISSUtil.convertNullToSpace(obj2));
return example;
}catch(Exception e) {
e.printStackTrace();
example.setobj1(ISSUtil.convertNullToSpace(""));//setting
objects to "" in exception block
example.setobj1(ISSUtil.convertNullToSpace(""));
}
return example;
}`
Answer : Obviously when there is no records getsingleresult will throw an exception i have handled it by setting the objects to "" in the exception block even though it enter the exception you JSON object will set to ""/empty
Hope this is not a perfect answer but it might help
If some needs to modify my code more precisely and correct me always welcome.
Thats works to me:
Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : null;
Related
I am running a query on the DynamoDB GlobalSecondaryIndex. Post query, I want to check how much capacity I consumed. Based on the documentation, the ItemCollection provides a method getAccumulatedConsumedCapacity that does exactly this. However, when I try to use this in my code, it always returns NULL.
private void dummyMethod(QuerySpec querySpec) {
ItemCollection<QueryOutcome> queryOutcomes = index.query(querySpec);
Iterator<Item> itemIterator = queryOutcomes.iterator();
while(itemIterator.hasNext()) {
Map<String, Object> itemAsMap = itemIterator.next().asMap();
// do something with itemAsMap
}
if(queryOutcomes.getAccumulatedConsumedCapacity() == null) {
LOGGER.error("capacity is null");
}
}
There was no problem with this piece of code. The bug was in the caller method. In order for the results to return the consumed capacity, we have to explicitly set ReturnConsumedCapacity field.
For example: withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);.
I can't figure out how to factor out this code.
private CompletionStage<Response<String>> foo(RequestContext rc) {
final Optional<String> campaignIdOpt = rc.request().parameter("campaignId").filter(s -> !s.isEmpty());
final Optional<String> creativeIdOpt = rc.request().parameter("creativeId").filter(s -> !s.isEmpty());
Optional<Uuid> campaignIdOptOfUuid = Optional.empty();
if (campaignIdOpt.isPresent()) {
try {
campaignIdOptOfUuid = Optional.of(UuidUtils.fromString(campaignIdOpt.get()));
} catch (IllegalArgumentException e) {
LOG.error(String.format("Invalid campaignId: %s", campaignIdOpt.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST.withReasonPhrase("Invalid campaignId provided.")));
}
}
Optional<Uuid> creativeIdOptOfUuid = Optional.empty();
if (creativeIdOpt.isPresent()) {
try {
creativeIdOptOfUuid = Optional.of(UuidUtils.fromString(creativeIdOpt.get()));
} catch (IllegalArgumentException e) {
LOG.error(String.format("Invalid creativeId: %s", creativeIdOpt.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST.withReasonPhrase("Invalid creativeId provided.")));
}
}
// Simplified, do something with Uuids.
return bar(campaignIdOptOfUuid, creativeIdOptOfUuid);
}
Basically, we very frequently need to parse Google protobuf Uuids from a query string to pass on to another service that will find (or not find). We need to pass along an empty optional if a parameter was not set or an empty string, as both cases mean, "Don't filter by this parameter." Finally, if the string doesn't parse at all, then we want to immediately return an error 400 (Bad Request), rather than pass along a non-sense param to the service.
So, codewise, I want a utility method that
takes an Optional<String>, and
returns an Optional<Uuid> if present, Optional.empty() otherwise, and
if an exception is thrown, return an error from the original context.
But obviously, I can't "double-return." What pattern do I use to achieve this though? I tried to create an encapsulator for both an Optional<Uuid> and a CompletionStage<Response<String>> but it was awkward. Is there some idiomatic way of doing this?
You can use a loop. A loop allows you to handle all elements equally, thus removing the code duplication, while still allowing to return immediately:
private CompletionStage<Response<String>> foo(RequestContext rc) {
String[] parameters = {"campaignId", "creativeId" };
List<Optional<Uuid>> uuids = new ArrayList<>(parameters.length);
for(String param: parameters) {
Optional<String> o1 = rc.request().parameter(param).filter(s -> !s.isEmpty());
Optional<Uuid> o2;
try {
o2 = o1.map(UuidUtils::fromString);
} catch(IllegalArgumentException e) {
LOG.error(String.format("Invalid %s: %s", param, o1.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST
.withReasonPhrase("Invalid "+param+ " provided.")));
}
uuids.add(o2);
}
// Simplified, do something with Uuids.
return bar(uuids.get(0), uuids.get(1));
}
Otherwise, you would need to create a method returning an object holding two alternative results (like Either); the JDK does not provide such a type yet. A method could simply throw on an erroneous condition but that would bring you back to square one when the common code is mostly the exception handling.
Note that calling Optional.map on an empty optional will already return an empty optional, without evaluating the provided function, so you don’t need to check via ifPresent, etc.
So, I have the following method which is faking a database locally:
public class TestClassDao implements ClassDao {
// ...
private static List<ClassDto> classes = new ArrayList<>();
#Override
public List<ClassDto> getClassesByIds(List<Long> classIds) {
List<ClassDto> results = new ArrayList<>();
for (ClassDto classInstance : classes) {
if (classIds.contains(classInstance.getId())) {
results.add(classInstance);
}
}
return cloner.deepClone(results);
}
//...
}
I was puzzled, because the results were always coming back empty. I stepped through the debugger in Android Studio, and found that the contains check is always returning false even when the right ID is known to be present.
Tracing that back with the debugger, I found what I suspect to be the culprit: according to the debugger, List<Long> classIds contains *Integer* objects. What gives? I'm not sure how to debug this any further.
EDIT:
Here's the debugger output the question is based on:
EDIT 2:
Here's how the test data is being loaded into the data store, you can see I am correctly passing Long values:
The below method is called by a method which does a similar thing for schools, and then persisted via a method in the test DAO.
public static ClassDto getClassTestData(int classId) {
ClassDto classDto = new ClassDto();
switch (classId) {
case 1:
classDto.setId(1L);
classDto.setName("207E - Mrs. Randolph");
classDto.setTeacher(getTeacherTestData());
classDto.setStudents(getStudentsTestData());
return classDto;
case 2:
classDto.setId(2L);
classDto.setName("209W - Mr. Burns");
classDto.setTeacher(getTeacherTestData());
return classDto;
case 3:
classDto.setId(3L);
classDto.setName("249E - Mr. Sorola");
classDto.setTeacher(getTeacherTestData());
return classDto;
default:
return null;
}
}
EDIT 3:
Here is the DAO where the school information is being persisted/retrieved from. The problem is occuring somewhere between the time that the data is inserted and the time it is removed. It goes in with type Long and comes out with Type Int
#Dao
public interface SchoolDao {
#Query("SELECT * FROM schools")
List<SchoolDto> getAllSchools();
#Insert
void insertSchool(SchoolDto schoolDto);
}
Wow, what a nightmare. I have found the culprit.
I had created a TypeConverter to turn a List<Integer> to into a string (and back) so that it can be stored in a single column in the DB in room without having to modify the existing DTOs. However, when I switched over to using Long types as IDs, I failed to convert a single generic argument below in the converter; look carefully at the following code:
public class IdsListConverter {
#TypeConverter
public List<Long> idsFromString(String value) {
Gson gson = new Gson();
if (value == null || value.isEmpty()) {
return null;
} else {
Type resultType = new TypeToken<List<Integer>>(){}.getType();
return gson.fromJson(value, resultType);
}
}
#TypeConverter
public String idsToString(List<Long> ids) {
if (ids == null) {
return null;
} else {
Gson gson = new Gson();
return gson.toJson(ids);
}
}
}
It looks like you found your problem:
Type resultType = new TypeToken<List<Integer>>(){}.getType();
return gson.fromJson(value, resultType);
(in a method returning List<Long>) whereas it should have been:
Type resultType = new TypeToken<List<Long>>(){}.getType();
There is a type-safe way to write this which would have picked up the problem at compile time:
TypeToke<List<Integer>> resultTypeToken = new TypeToken<List<Integer>>() {};
return gson.getAdapter(resultTypeToken).fromJson(value);
This wouldn't have compiled, because the return statement's type is incompatible with the method's return type.
It might be worth looking for other occurrences of fromJson so you can migrate them and see if there are other problems you haven't found yet!
You look at wrong variables. ClassDao instance is below, you can see "{Long#6495} "1". But the Integer "1" you spread is the element of ClassIds which is omitted in your code. You are sure ClassIds is List(), when adding element, you should do classIds.add(new Long(1)).
For future reference, this list of casting rules will help you. In essence, I believe there is/was an implicit casting conflict.
byte –> short –> int –> long –> float –> double
I have a very strange issue with hibernate and jpa. Below are two blocks of code:
public Object getObject(Date date) {
try {
Query query = entityManager
.createQuery(
"select ob from Object ob where date= :date");
query.setParameter("date", date);
return (Object)query.getSingleResult();
} catch (EmptyResultDataAccessException e) {
logger.debug(String.format("No Result found - date[%s]",date));
return null;
}
}
...
public Object getObject(Date date) {
try {
Query query = entityManager
.createQuery(
"select ob from Object ob where date= :date");
query.setParameter("date", date);
Object ret = (Object)query.getSingleResult();
return ret;
} catch (EmptyResultDataAccessException e) {
logger.debug(String.format("No Result found - date[%s]",date));
return null;
}
}
The first generates an EmptyResultDataAccessException every time even given a valid record where the date matches. The second returns a result as expected. Has anyone encountered this? What causes this behavior?
Please assume all other syntatical things are present(a transaction, initialized entitymanager, etc) the only thing that I change is whether the query results are retrieved directly in the return or assigned to a variable first.
It IS possible, I encountered it before as well. I think it has something to do with byte code manipulations that Hibernate is doing. To get to the root of it, you have to go to a very deep and dark level of implementation.
When working with Hibernate/JPA I always use the second pattern. It's unfortunate because it makes the code a bit more verbose, but it's not worth plunging into a depth of generated byte code and trying to comprehend it.
That's not possible. The two variants are equivalent. There's something you are missing perhaps.
Note that getSingleResult() can throw an exception if there is more than 1 result.
I'm looking for a Google Collections method that returns the first result of a sequence of Suppliers that doesn't return null.
I was looking at using Iterables.find() but in my Predicate I would have to call my supplier to compare the result against null, and then have to call it again once the find method returned the supplier.
Given your comment to Calm Storm's answer (the desire not to call Supplier.get() twice), then what about:
private static final Function<Supplier<X>, X> SUPPLY = new Function<....>() {
public X apply(Supplier<X> in) {
// If you will never have a null Supplier, you can skip the test;
// otherwise, null Supplier will be treated same as one that returns null
// from get(), i.e. skipped
return (in == null) ? null : in.get();
}
}
then
Iterable<Supplier<X>> suppliers = ... wherever this comes from ...
Iterable<X> supplied = Iterables.transform(suppliers, SUPPLY);
X first = Iterables.find(supplied, Predicates.notNull());
note that the Iterable that comes out of Iterables.transform() is lazily-evaluated, therefore as Iterables.find() loops over it, you only evaluate as far as the first non-null-returning one, and that only once.
You asked for how to do this using Google Collections, but here's how you would do it without using Google Collections. Compare it to Cowan's answer (which is a good answer) -- which is easier to understand?
private static Thing findThing(List<Supplier<Thing>> thingSuppliers) {
for (Supplier<Thing> supplier : thingSuppliers) {
Thing thing = supplier.get();
if (thing != null) {
return thing;
}
}
// throw exception or return null
}
In place of the comment -- if this was the fault of the caller of your class, throw IllegalArgumentException or IllegalStateException as appropriate; if this shouldn't have ever happened, use AssertionError; if it's a normal occurrence your code that invokes this expects to have to check for, you might return null.
What is wrong with this?
List<Supplier> supplierList = //somehow get the list
Supplier s = Iterables.find(supplierList, new Predicate<Supplier>(){
boolean apply(Supplier supplier) {
return supplier.isSomeMethodCall() == null;
}
boolean equals(Object o) {
return false;
}
});
Are you trying to save some lines? The only optimisation I can think is to static import the find so you can get rid of "Iterables". Also the predicate is an anonymous inner class, if you need it in more than one place you can create a class and it would look as,
List<Supplier> supplierList = //somehow get the list
Supplier s = find(supplierList, new SupplierPredicateFinder());
Where SupplierPredicateFinder is another class.
UPDATE : In that case find is the wrong method. You actually need a custom function like this which can return two values. If you are using commons-collections then you can use a DefaultMapEntry or you can simply return an Object[2] or a Map.Entry.
public static DefaultMapEntry getSupplier(List<Supplier> list) {
for(Supplier s : list) {
Object heavyObject = s.invokeCostlyMethod();
if(heavyObject != null) {
return new DefaultMapEntry(s, heavyObject);
}
}
}
Replace the DefaultMapEntry with a List of size 2 or a hashmap of size 1 or an array of length 2 :)