Spring Data JPA findOne() change to Optional how to use this? - java

I'm learning SpringBoot2.0 with Java8.
And I followed some blog-making tutorial example.
The tutorial source code is:
#GetMapping("/{id}/edit")
public String edit(#PathVariable Long id, Model model) {
model.addAttribute("categoryDto", categoryService.findOne(id));
return "category/edit";
}
But this code is throwing this error:
categoryService.findOne(id)
I'm thinking about changing the JPA findOne() method to Optional< S >
How to solve that?
More info:
This is the categoryService method:
public Category findOne(Long id) {
return categoryRepository.findOne(id);
}

From at least, the 2.0 version, Spring-Data-Jpa modified findOne().
Now, findOne() has neither the same signature nor the same behavior.
Previously, it was defined in the CrudRepository interface as:
T findOne(ID primaryKey);
Now, the single findOne() method that you will find in CrudRepository is the one defined in the QueryByExampleExecutor interface as:
<S extends T> Optional<S> findOne(Example<S> example);
That is implemented finally by SimpleJpaRepository, the default implementation of the CrudRepository interface.
This method is a query by example search and you don't want that as a replacement.
In fact, the method with the same behavior is still there in the new API, but the method name has changed.
It was renamed from findOne() to findById() in the CrudRepository interface :
Optional<T> findById(ID id);
Now it returns an Optional, which is not so bad to prevent NullPointerException.
So, the actual method to invoke is now Optional<T> findById(ID id).
How to use that?
Learning Optional usage.
Here's important information about its specification:
A container object which may or may not contain a non-null value. If a
value is present, isPresent() will return true and get() will return
the value.
Additional methods that depend on the presence or absence of a
contained value are provided, such as orElse() (return a default value
if value not present) and ifPresent() (execute a block of code if the
value is present).
Some hints on how to use Optional with Optional<T> findById(ID id).
Generally, as you look for an entity by id, you want to return it or make a particular processing if that is not retrieved.
Here are three classical usage examples.
Suppose that if the entity is found you want to get it otherwise you want to get a default value.
You could write :
Foo foo = repository.findById(id)
.orElse(new Foo());
or get a null default value if it makes sense (same behavior as before the API change) :
Foo foo = repository.findById(id)
.orElse(null);
Suppose that if the entity is found you want to return it, else you want to throw an exception.
You could write :
return repository.findById(id)
.orElseThrow(() -> new EntityNotFoundException(id));
Suppose you want to apply a different processing according to if the entity is found or not (without necessarily throwing an exception).
You could write :
Optional<Foo> fooOptional = fooRepository.findById(id);
if (fooOptional.isPresent()) {
Foo foo = fooOptional.get();
// processing with foo ...
} else {
// alternative processing....
}

The method has been renamed to findById(…) returning an Optional so that you have to handle absence yourself:
Optional<Foo> result = repository.findById(…);
result.ifPresent(it -> …); // do something with the value if present
result.map(it -> …); // map the value if present
Foo foo = result.orElse(null); // if you want to continue just like before

Indeed, in the latest version of Spring Data, findOne returns an optional. If you want to retrieve the object from the Optional, you can simply use get() on the Optional. First of all though, a repository should return the optional to a service, which then handles the case in which the optional is empty. afterwards, the service should return the object to the controller.

I always write a default method "findByIdOrError" in widely used CrudRepository repos/interfaces.
#Repository
public interface RequestRepository extends CrudRepository<Request, Integer> {
default Request findByIdOrError(Integer id) {
return findById(id).orElseThrow(EntityNotFoundException::new);
}
}

Optional api provides methods for getting the values. You can check isPresent() for the presence of the value and then make a call to get() or you can make a call to get() chained with orElse() and provide a default value.
The last thing you can try doing is using #Query() over a custom method.

The findOne method of the CrudRepository interface has been replaced by findById since version 2.0 of Spring Data Commons.
you replace findOne(id) by:
findById(id).orElse(null)

Consider an User entity and UserRepository. In service package code like below.
Optional<User> resultUser = UserRepository.findById(userId); //return Optional
User createdUser = resultUser.get(); //return User
Now you can access all the User entity attributes using getter.
createdUser.getId();
createdUser.getName();
like that.

Related

How to use Optional in Java?

I have a Service which queries for a list of coupons from the database. This service returns an Optional to the client.
return listOfCoupons.isEmpty() ? Optional.empty() : Optional.of(listOfCoupons.get(listOfCoupons.size() - 1));
And the client of this code uses Optional named 'coupons' in the following way:
if (coupons.isPresent) {
save (coupons.get());
}
Is this the correct use of Optional ?
Your use of the Optional<T> API looks fine from afar as I cannot see any misuse of it. if I were to nitpick and suggest something I would change:
if (coupons.isPresent) {
save (coupons.get());
}
to:
coupons.ifPresent(c -> save(c)); //or method reference
but then again that's down to taste really.

Apply Spring JPA Specification to multiple repositories and queries

I have the following situation:
My project contains multiple entities, each one with its respective controller, service and JPA repository. All of these entities are associated with a specific company by a "companyUuid" property.
Every incoming request in my controllers will have a "user" header, which will give me the details of the User making that request, including which company he is associated with.
I need to retrieve the company associated with the user from the header and filter every subsequent query by this company, which would be essentially like adding WHERE companyUuid = ... to each query.
What I did as a solution was a generic function for creating the Specification object:
public class CompanySpecification {
public static <T> Specification<T> fromCompany(String companyUuid) {
return (e, cq, cb) -> cb.equal(e.get("companyUuid"), companyUuid);
}}
Implemented repository as follows:
public interface ExampleRepository extends JpaRepository<Example, Long>, JpaSpecificationExecutor<Example> { }
Changed the "find" calls to include the specification:
exampleRepository.findAll(CompanySpecification.fromCompany(companyUuid), pageRequest);
Of course, this requires adding #RequestHeader to the controller functions to get the user in the header.
Although this solution works absolutely fine, it would require a lot of copy-pasting and code repetition to get it done for all routes of my #RestControllers.
Therefore, the question is: how can I do this in an elegant and clean way for all my controllers?
I have researched this quite a bit now and I came across the following conclusions:
Spring JPA and Hibernate don't seem to provide a way of dynamically using a Specification to restrict all queries (reference: Automatically Add criteria on each Spring Jpa Repository call)
Spring MVC HandlerInterceptor would maybe help for getting the User out of the header in each request, but it doesn't seem to fit overall since I don't use views in this project (it's just a back-end) and it can't do anything about my repository queries
Spring AOP seemed like a great option to me and I gave it a go. My intention was to keep all repository calls as they were, and add the Specification to the repository call. I created the following #Aspect:
#Aspect
#Component
public class UserAspect {
#Autowired(required=true)
private HttpServletRequest request;
private String user;
#Around("execution(* com.example.repository.*Repository.*(..))")
public Object filterQueriesByCompany(ProceedingJoinPoint jp) throws Throwable {
Object[] arguments = jp.getArgs();
Signature signature = jp.getSignature();
List<Object> newArgs = new ArrayList<>();
newArgs.add(CompanySpecification.fromCompany(user));
return jp.proceed(newArgs.toArray());
}
#Before("execution(* com.example.controller.*Controller.*(..))")
public void getUser() {
user = request.getHeader("user");
}
}
This would have worked perfectly, since it would require almost no modifications at all to controllers, services and repositories. Although, I had a problem with the function signature. Since I am calling findAll(Pageable p) in my Service, the signature of the function is already defined in my advice, and I can't change to the alternative version findAll(Specification sp, Pageagle p) from inside the advice.
What do you think would be the best approach in this situation?
Here is an idea:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
#Aspect
public class UserAspect {
#Around("execution(* com.example.repository.*Repository.findAll())")
public Object filterQueriesByCompany(ProceedingJoinPoint jp) throws Throwable {
Object target = jp.getThis();
Method method = target.getClass().getMethod("findAll", Specification.class);
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
return method.invoke(target, CompanySpecification.fromCompany(request.getHeader("user")));
}
}
The above aspect intercepts the findAll() methods from repository and, instead of proceeding the call it replaces with another call to findAll(Specification) method. Notice how I get the HttpServletRequest instance.
Of course, it's a starting point not an out of the box solution.
I am not a Spring or Java EE user, but I can help you with the aspect part. I googled a bit, too, because your code snippets without imports and package names are a bit incoherent, so I cannot just copy, paste and run them. Judging from the JavaDocs for JpaRepository and JpaSpecificationExecutor, both of which you extend in your ExampleRepository, you are trying to intercept
Page<T> PagingAndSortingRepository.findAll(Pageable pageable)
(inherited by JpaRepository) and call
List<T> JpaSpecificationExecutor.findAll(Specification<T> spec, Pageable pageable)
instead, right?
So in theory we can use this knowledge in our pointcut and advice in order to be more type-safe and avoid ugly reflection tricks. The only problem here is that the intercepted call returns Page<T> while the method you want to call instead returns List<T>. The calling method surely expects the former and not the latter, unless you always use Iterable<T> which is a super-interface for both interfaces in question. Or maybe you just ignore the return value? Without you answering that question or showing how you modified your code to do this, it will be difficult to really answer your question.
So let us just assume that the returned result is either ignored or handled as Iterable. Then your pointcut/advice pair looks like this:
#Around("execution(* findAll(*)) && args(pageable) && target(exampleRepository)")
public Object filterQueriesByCompany(ProceedingJoinPoint thisJoinPoint, Pageable pageable, ExampleRepository exampleRepository) throws Throwable {
return exampleRepository.findAll(CompanySpecification.fromCompany(user), pageable);
}
I tested it, it works. I also think it is a bit more elegant, type-safe and readable than what you tried or what was proposed by Eugen.
P.S.: Another option is to convert the list into a corresponding page manually before returning it from the aspect advice if the calling code indeed expects a page object to be returned.
Update due to follow-up question:
Eugen wrote:
For another entity, let's say Foo, the repository would be public interface FooRepository extends JpaRepository<Foo, Long>, JpaSpecificationExecutor<Foo> { }
Well, then let us just generalise the pointcut and assume that it should always target classes which extend both interfaces in question:
#Around(
"execution(* findAll(*)) && " +
"args(pageable) && " +
"target(jpaRepository) && " +
//"within(org.springframework.data.jpa.repository.JpaRepository+) && " +
"within(org.springframework.data.jpa.repository.JpaSpecificationExecutor+)"
)
public Object filterQueriesByCompany(ProceedingJoinPoint thisJoinPoint, Pageable pageable, JpaRepository jpaRepository) throws Throwable {
return ((JpaSpecificationExecutor) jpaRepository)
.findAll(CompanySpecification.fromCompany(user), pageable);
}
The part of the pointcut I commented out is optional because I am narrowing down to JpaRepository method calls already via target() parameter binding using the advice signature. The second within() should be used, however, in order to make sure the intercepted class actually also extends the second interface so we can cast and execute the other method instead without any problems.
Update 2:
As Eugen said, you can also get rid of the cast if you bind the target object to the type JpaSpecificationExecutor - but only if you do not need the JpaRepository in your advice code before that. Otherwise you would have to cast the other way. Here it seems it is not really needed, so his idea makes the solution a little more lean and expressive, indeed. Thanks for the contribution. :-)
#Around(
"target(jpaSpecificationExecutor) && " +
"execution(* findAll(*)) && " +
"args(pageable) && " +
"within(org.springframework.data.jpa.repository.JpaRepository+)"
)
public Object filterQueriesByCompany(ProceedingJoinPoint thisJoinPoint, Pageable pageable, JpaSpecificationExecutor jpaSpecificationExecutor) throws Throwable {
return jpaSpecificationExecutor.findAll(CompanySpecification.fromCompany(user), pageable);
}
Or alternatively, if you do not want to merge execution() with within() (a matter of taste):
#Around(
"target(jpaSpecificationExecutor) && " +
"execution(* org.springframework.data.jpa.repository.JpaRepository+.findAll(*)) && " +
"args(pageable)"
)
public Object filterQueriesByCompany(ProceedingJoinPoint thisJoinPoint, Pageable pageable, JpaSpecificationExecutor jpaSpecificationExecutor) throws Throwable {
return jpaSpecificationExecutor.findAll(CompanySpecification.fromCompany(user), pageable);
}
Less type-safe, but also an option if you believe that the are no other classes with * findAll(Pageable) signature:
#Around("target(jpaSpecificationExecutor) && execution(* findAll(*)) && args(pageable)")
public Object filterQueriesByCompany(ProceedingJoinPoint thisJoinPoint, Pageable pageable, JpaSpecificationExecutor jpaSpecificationExecutor) throws Throwable {
return jpaSpecificationExecutor.findAll(CompanySpecification.fromCompany(user), pageable);
}
You might notice that this suspiciously looks like my original solution for one specific sub-interface, and you are right. I recommend to be a little more strict, though, and not use the last option, even though it works in my test case and you would probably be fine with it.
Finally, I think we have covered most bases by now.

Getting single NonNull value using Spring Data

I'd like to have a method in my Repository that returns a single value.
Like this:
TrainingMode findByTrainingNameAndNameEng( String trainingName, String nameEng );
http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/
Spring Data Docs describe that in this case the method can return null if no entity is found.
I'd like to throw an exception with generic message like No TrainingMode found by %trainingName% and %nameEng% or smth like that.
I can use Optional<TrainingMode> as a return value and then use orElseThrow
Optional<TrainingMode> findByTrainingNameAndNameEng( String trainingName, String nameEng );
repository.findByTrainingNameAndNameEng(name, nameEng).orElseThrow(() -> new RuntimeException(...));
But I should call this method each time when this method is called. It's not clear - DRY priciple is broken.
How to get nonnull single value with orElseThrow using Spring Data?
The DRY principle would be violated if you duplicate null handling throughout the application logic where it is being invoked. If DRY principle is the thing you are worried the most then i can think of:
You can make a "Service" class which would delegate calls to annotated repository and handle null response logic to it, and use that service class instead of calling repositories directly. Drawback would be introducing another layer to your application (which would decouple repositories from your app logic).
There is possibility of adding custom behavior to your data repositories which is described in "3.6.1. Adding custom behavior to single repositories" section of documentation. Sorry for not posting the snippet.
The issue I personally have with second approach is that it pollutes app with interfaces, enforces you to follow a certain naming patterns (never liked 'Impl' suffixes), and might make migrating code a bit more time consuming (when app becomes big it becomes harder to track which interface is responsible for which custom behavior and then people just simply start creating their own behavior which turns out to be duplicate of another).
I found a solution.
First, Spring Data processes getByName and findByName equally. And we can use it: in my case find* can return null (or returns not null Optional, as you wish) and get* should return only value: if null is returned then exception is thrown.
I decided to use AOP for this case.
Here's the aspect:
#Aspect
#Component
public class GetFromRepositoryAspect {
#Around("execution(public !void org.springframework.data.repository.Repository+.get*(..))")
public Object aroundDaoMethod( ProceedingJoinPoint joinpoint ) throws Throwable {
Object result = joinpoint.proceed();
if (null == result) {
throw new FormattedException( "No entity found with arhs %s",
Arrays.toString( joinpoint.getArgs() ) );
}
return result;
}
}
That's all.
You can achieve this by using the Spring nullability annotations. If the method return type is just some Entity and it's not a wrapper type, such as Optional<T>, then org.springframework.dao.EmptyResultDataAccessException will be thrown in case of no results.
Read more about Null Handling of Repository Methods.

Proper usage of Optional.ifPresent()

I am trying to understand the ifPresent() method of the Optional API in Java 8.
I have simple logic:
Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));
But this results in a compilation error:
ifPresent(java.util.functionError:(186, 74) java: 'void' type not allowed here)
Of course I can do something like this:
if(user.isPresent())
{
doSomethingWithUser(user.get());
}
But this is exactly like a cluttered null check.
If I change the code into this:
user.ifPresent(new Consumer<User>() {
#Override public void accept(User user) {
doSomethingWithUser(user.get());
}
});
The code is getting dirtier, which makes me think of going back to the old null check.
Any ideas?
Optional<User>.ifPresent() takes a Consumer<? super User> as argument. You're passing it an expression whose type is void. So that doesn't compile.
A Consumer is intended to be implemented as a lambda expression:
Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));
Or even simpler, using a method reference:
Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);
This is basically the same thing as
Optional<User> user = ...
user.ifPresent(new Consumer<User>() {
#Override
public void accept(User theUser) {
doSomethingWithUser(theUser);
}
});
The idea is that the doSomethingWithUser() method call will only be executed if the user is present. Your code executes the method call directly, and tries to pass its void result to ifPresent().
In addition to #JBNizet's answer, my general use case for ifPresent is to combine .isPresent() and .get():
Old way:
Optional opt = getIntOptional();
if(opt.isPresent()) {
Integer value = opt.get();
// do something with value
}
New way:
Optional opt = getIntOptional();
opt.ifPresent(value -> {
// do something with value
})
This, to me, is more intuitive.
Why write complicated code when you could make it simple?
Indeed, if you are absolutely going to use the Optional class, the most simple code is what you have already written ...
if (user.isPresent())
{
doSomethingWithUser(user.get());
}
This code has the advantages of being
readable
easy to debug (breakpoint)
not tricky
Just because Oracle has added the Optional class in Java 8 doesn't mean that this class must be used in all situation.
You can use method reference like this:
user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);
Method ifPresent() get Consumer object as a paremeter and (from JavaDoc): "If a value is present, invoke the specified consumer with the value." Value it is your variable user.
Or if this method doSomethingWithUser is in the User class and it is not static, you can use method reference like this:
user.ifPresent(this::doSomethingWithUser);
Use flatMap. If a value is present, flatMap returns a sequential Stream containing only that value, otherwise returns an empty Stream. So there is no need to use ifPresent() . Example:
list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());

Custom object filter for a grid column in sencha GXT

Important edit: I added a depth level to the situation to better reflect my problem.
I have a GXT Grid with a ListStore of a certain type Foo. Foo happens to have some important object properties, including one of type Bar. Type Bar consists of two object properties: fooFoo of type FooFoo and barBar of type Barbar. These two can be null and have a String property description.
I want to use the GXT grid's filtering to filter the Foo object records' by their Bar value's FooFoo or BarBar description.
I tried to add a ValueProvider<Foo, String> barDescription(); to FooProperties, resulting in:
StringFilter<Foo> barbarFilter = new StringFilter<Foo>(fooProps.barbarDescription());
In which Foo#getBarBarDescription() is implemented as follows:
public String getBarBarDescription() {
return this.getBar().getBarBar().getDescription();
}
Is there a simple/convenient way to implement this behaviour in GXT? I have not found it.
The implementation I describe above is the one I have tried, but the filters don't show up in the grid at all, no further error messages.
In response to Colin's answer to the previous version of my question, I have tried the following:
#Path("bar.barbar.description")
ValueProvider<Foo, String> barbarDescription();
Hoping for it to call Foo#getBar().getBarBar().getDescription(). I suspect the possibility for FooFoo and BarBar to be null may be causing issues.
If you want to have barDescription() invoke getBar().getDescription() on your Foo objects, then try this:
public interface FooProperties extends PropertyAccess<Foo> {
#Path("bar.description")
ValueProvider<Foo, String> barDescription();
//...
}
The #Path annotation works the same here as it does in the editor framework - you can use it to specify the path to the property you want access to. This allows you to skip creating a getBarDescription() method in your own Foo object.
Another option is to just build your own ValueProvider implementation. Using PropertyAccess is a way to ask the compiler to do the work for you, but nothing stops you from doing it yourself. In this case, it might look like this:
public class FooBarDescriptionValueProvider implements ValueProvider<Foo, String> {
public String getValue(Foo object) {
//TOOD consider a object.getBar() null check?
return object.getBar().getDescription();
}
public void setValue(Foo object, String value) {
object.getBar().setDescription(value);
}
public String getPath() {
return "bar.description";
}
}
Note that this is almost exactly what the PropertyAccess generated version will look like, but it allows you to customize the behavior however you want.

Categories