Customizing Param Binding for QueryDSL Support - spring-data

I have a Spring Data Rest repository which utilises the QueryDSL support outlined here:
https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#spring-data-rest
The default is to query all specified parameters using equals. A mechanism to override the param binding to something other than equals is given in the same article however it requires Java 8.
https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#querydsl-web-support
Is there any clean way in Java 7 to achieve the same functionality?
Update
I can get the binding customization working as below:
#Override
public void customize(QuerydslBindings bindings, QMember member) {
bindings.bind(member.forename).first(new SingleValueBinding<StringPath, String>() {
#Override
public Predicate bind(StringPath path, String value) {
return path.like(value);
}
});
bindings.bind(member.surname).first(new SingleValueBinding<StringPath, String>() {
#Override
public Predicate bind(StringPath path, String value) {
return path.startsWith(value);
}
});
}
However the examples all use a Java 8 default method on the repository interface to have them applied.
public interface MemberRepository extends JpaRepository<Member, Long>,
QueryDslPredicateExecutor<Member>,QuerydslBinderCustomizer<QMember> {
default void customize(QuerydslBindings bindings, QMember member) {
....
}
}
In Java 7 this is obviously not possible. I have tried with a custom repository however that fails with an error:
org.springframework.data.mapping.PropertyReferenceException: No property customize found for type Member!
public interface MemberRepositoryCustom {
public void customize(QuerydslBindings bindings, QMember member);
}
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
#Override
public void customize(QuerydslBindings bindings, QMember member) {
bindings.bind(member.forename).first(new SingleValueBinding<StringPath, String>() {
#Override
public Predicate bind(StringPath path, String value) {
return path.like(value);
}
});
bindings.bind(member.surname).first(new SingleValueBinding<StringPath, String>() {
#Override
public Predicate bind(StringPath path, String value) {
return path.startsWith(value);
}
});
}
}

There are two ways that you can accomplish this using Java 7. The first way is to create a generic base repository that will apply the custom bindings to all of the implemented model repositories. For example:
public class GenericModelRepository<T, ID extends Serializable, S extends EntityPath<T>> extends QueryDslJpaRepository<T, ID> implements QuerydslBinderCustomizer<S> {
public GenericModelRepository(
JpaEntityInformation<T, ID> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
}
public GenericModelRepository(
JpaEntityInformation<T, ID> entityInformation,
EntityManager entityManager,
EntityPathResolver resolver) {
super(entityInformation, entityManager, resolver);
}
#Override
public void customize(QuerydslBindings bindings, S t) {
bindings.bind(String.class).first(new SingleValueBinding<StringPath, String>() {
#Override
public Predicate bind(StringPath path, String s) {
return path.equalsIgnoreCase(s);
}
});
}
}
To tell Spring Data to use this base repository when implementing all of your custom repository interfaces, simply add it as the repositoryBaseClass in the #EnableJpaRepositories annotation:
#Configuration
#EnableJpaRepositories(basePackages = { "me.woemler.project.repositories" }, repositoryBaseClass = GenericModelRepository.class)
#EnableTransactionManagement
public class RepositoryConfig { ... }
#RepositoryRestResource
public interface PersonRepository extends JpaRepository<Person, Long>,
QueryDslPredicateExecutor<Person>,
QuerydslBinderCustomizer<EntityPath<Person>> {
}
Now all web service StringPath query operations will be case-insensitive equality tests:
GET http://localhost:8080/persons?name=joe%20smith
"_embedded": {
"persons": [
{
"name": "Joe Smith",
"gender": "M",
"age": 35,
"_links": {
"self": {
"href": "http://localhost:8080/persons/1"
},
"person": {
"href": "http://localhost:8080/persons/1"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/persons"
},
"profile": {
"href": "http://localhost:8080/profile/persons"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
The second option, should you want more fine control over how each repository handling its bindings would be to create an Impl version of the repositories you wish to customize:
public class PersonRepositoryImpl implements QuerydslBinderCustomizer<EntityPath<Person>> {
#Override
public void customize(QuerydslBindings bindings, EntityPath<Person> t) {
bindings.bind(String.class).first(new SingleValueBinding<StringPath, String>() {
#Override
public Predicate bind(StringPath path, String s) {
return path.equalsIgnoreCase(s);
}
});
}
}
You can then use the #EnableJpaRepositories annotation normally, but you must create an Impl instance for each of your repository interfaces that you wish to customize.

you can use the
BooleanBuilder
import com.mysema.query.BooleanBuilder;
to construct the queryDsl predicate
QUser quser=QUser.User;
BooleanBuilder whereClause=new BooleanBuilder();
whereClause.and(quser.property1.eq("some"));
whereClause.and(quser.property2.in(listOfValues));
springRepository.find(whereClause);
FootNote: java 8 would help reduce a lot of keystrokes for the above case

Related

Dagger 2 Subcomponents for Encapsulation

How do I add a Subcomponent to a Module with an argument constructor?
Adding code here in addition to providing a github link:
ExampleApplication.java
public class ExampleApplication extends DaggerApplication {
#Inject
Database database;
#Override
public void onCreate() {
super.onCreate();
Timber.plant(new Timber.DebugTree());
Timber.i(database.name());
}
#Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerApplicationComponent
.builder()
.application(this)
.build();
}
}
ApplicationComponent.java
#ApplicationScope
#Component(modules = {
ApplicationModule.class,
AndroidSupportInjectionModule.class,
ActivityBindingModule.class,
DatabaseModule.class,
})
public interface ApplicationComponent extends AndroidInjector<ExampleApplication> {
Database database();
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
ApplicationComponent build();
}
#Override
void inject(ExampleApplication instance);
}
DatabaseModule.java
#Module(subcomponents = DatabaseComponent.class)
public class DatabaseModule {
#Provides
#ApplicationScope
Database provideDatabase(
#NumberOfCores int numberOfCores,
DatabaseComponent.Builder databaseComponentBuilder) {
return databaseComponentBuilder
.databaseImplModule(new DatabaseImplModule(numberOfCores / 2))
.build()
.database();
}
}
DatabaseComponent.java
#Subcomponent(modules = DatabaseImplModule.class)
public interface DatabaseComponent {
// #PrivateToDatabase <- Is this a qualifier? A scope? Neither?
Database database();
#Subcomponent.Builder
interface Builder {
Builder databaseImplModule(DatabaseImplModule databaseImplModule);
DatabaseComponent build();
}
}
DatabaseImplModule.java
#Module
public class DatabaseImplModule {
DatabaseImplModule(int concurrencyLevel) {}
#Provides DatabaseConnectionPool provideDatabaseConnectionPool() {
return new DatabaseConnectionPool();
}
#Provides DatabaseSchema provideDatabaseSchema() {
return new DatabaseSchema();
}
}
Database.java
public class Database {
#Inject
public Database() { }
public String name() {
return "I have a name";
}
}
I tried to take a look at the dagger subcomponents documentation, specifically the section Subcomponents for encapsulation. I tried to create a code example
to see if I could make it work, but with no luck. Am I missing something in the documentation? (There is a line of code commented out the #PrivateToDatabase which I am not sure what kind of annotation it is).

Autofac register multiple implementation from a single interface

How do I register this on Autofac given the code snippet below?
public interface IService
{
IEnumerable<string> GetNames();
}
public class GospelNames : IService
{
public IEnumerable<string> GetNames() { return new List<string>{ "John", "Mark" };}
}
public class CommonNames : IService
{
public IEnumerable<string> GetNames() { return new List<string>{ "Ben", "Matt" };}
}
public class WeirdNames : IService
{
public IEnumerable<string> GetNames() { return new List<string>{ "Weird Al" };}
}
public class BaseImplementation : IService
{
private readonly IEnumerable<IService> _services;
public BaseImplementation(params IService[] services)
{
_services = services;
}
public IEnumerable<string> GetNames()
{
var results = new List<string>();
foreach(var service in _services)
{
results.AddRange(service.GetNames());
}
return results;
}
}
I've been reading about decorator pattern and I'm not sure if this is a candidate to transform into that pattern? Or is this a bad practice?

Gwtp Autobean and rest

I have InfraNameModel (Rest-type) to work with JSON
public interface IInfraNameBeanFactory extends AutoBeanFactory {
IInfraNameBeanFactory INSTANCE = GWT.create(IInfraNameBeanFactory.class);
AutoBean<InfraNameModel> infraName();
AutoBean<InfraNameListModel> results();
}
public interface InfraNameListModel {
List<InfraNameModel> getResults();
void setResults(List<InfraNameModel> results);
}
public class InfraNameListModelImpl implements InfraNameListModel {
private List<InfraNameModel> results;
#Override
public List<InfraNameModel> getResults() {
return results;
}
#Override
public void setResults(List<InfraNameModel> results) {
this.results = results;
}
}
public interface InfraNameModel {
String getInfraName();
void setInfraName(String infraName);
}
public class InfraNameModelImpl implements InfraNameModel {
private String infraName;
#Override
public String getInfraName() {
return infraName;
}
#Override
public void setInfraName(String infraName) {
this.infraName = infraName;
}
}
I wanted to make them into a separate JAR
To make it common for the client and the server
But now I have errors
[WARN] Class by.models.infraNameModel.InfraNameModel is used in Gin, but not available in GWT client code.
Is it real to pull such beans into a separate library?

Injecting a Factory that accepts a Parameter with AutoFac

I've read over several examples that were more complex then I needed and I'm having trouble distilling this down to a simple, concise pattern.
Let's say I have an interface names ICustomService and multiple implementations of ICustomService. I also have a class Consumer that needs to determine at run time which ICustomService to use based upon a parameter.
So I create a classes as follows:
public class Consumer
{
private CustomServiceFactory customServiceFactory;
public Consumer(CustomServiceFactory _customServiceFactory)
{
customServiceFactory = _customServiceFactory;
}
public void Execute(string parameter)
{
ICustomService Service = customServiceFactory.GetService(parameter);
Service.DoSomething();
}
}
public class CustomServiceFactory
{
private IComponentContext context;
public CustomServiceFactory(IComponentContext _context)
{
context = _context;
}
public ICustomService GetService(string p)
{
return context.Resolve<ICustomService>(p); // not correct
}
}
public class ServiceA : ICustomService
{
public void DoSomething()
{
}
}
public class ServiceB : ICustomService
{
public void DoSomething()
{
}
}
Is there an advantage to having my factory implement an interface? How do I fix my factory and register these classes with Autofac so that Consumer.Execute("A") calls DoSomething on WorkerA and Consumer.Execute("B") calls DoSomething on WorkerB?
Thank you
You would register your implementations of ICustomService with keys. For example:
builder.RegisterType<FooService>.Keyed<ICustomService>("someKey");
builder.RegisterType<BarService>.Keyed<ICustomService>("anotherKey");
and then your factory method would be:
public ICustomService GetService(string p)
{
return context.ResolveKeyed<ICustomService>(p);
}
But, you can take this a step further and decouple CustomServiceFactory from IComponentContext:
public class CustomServiceFactory
{
private Func<string, ICustomService> _create;
public CustomServiceFactory(Func<string, ICustomService> create)
{
_create = create;
}
public ICustomService GetService(string p)
{
return _create(p);
}
}
which you would register like so:
builder.Register(c => {
var ctx = c.Resolve<IComponentContext>();
return new CustomServiceFactory(key => ctx.ResolveKeyed<ICustomService>(key));
});
And at that point, assuming CustomServiceFactory doesn't have any other behavior that was omitted for the question, then you as might as well just use and register Func<string, ICustomService> directly.

How to use provider in Errai IOC?

I have a problem with #IocProvider (), annotation does not work.
The code is very similar to https://docs.jboss.org/author/display/ERRAI/Container+Wiring
public interface Test {
String getGreeting();
}
#ApplicationScoped
public class TestImpl implements Test {
public String getGreeting() {
return "Hello:)";
}
}
#IOCProvider
#Singleton
public class TestProvider implements Provider<Test> {
#Override
public Test get() {
return new TestImpl();
}
}
Then I want use DI in my broadcast service (errai-bus).
#Service
public class BroadcastService implements MessageCallback {
#Inject
Test test;
#Inject
MessageBus bus;
#Inject
public BroadcastService(MessageBus bus) {
this.bus = bus;
}
public void callback(Message message) {
MessageBuilder.createMessage()
.toSubject("BroadcastReceiver")
.with("BroadcastText", test.getGreeting()).errorsHandledBy(new ErrorCallback() {
#Override
public boolean error(Message message, Throwable throwable) {
return true;
}
}).sendNowWith(bus);
}
}
I get a error:
1) No implementation for com.gwtplatform.samples.basic.server.Test was bound.
while locating com.gwtplatform.samples.basic.server.Test
for field at com.gwtplatform.samples.basic.server.BroadcastService.test(BroadcastService.java:32)
at org.jboss.errai.bus.server.service.ServiceProcessor$1.configure(ServiceProcessor.java:118)
If I change the code to
#Inject
TestImpl test;
It works, but I need the provider. Do you have some idea?
Because you're trying to use #IOCProvider in server-side code. Errai IOC is completely client-side.