I have the below Repository that extends CrudRepository. Now based on a property called "scopeName", we need to inject the collection name using #Collection("collectionName").
So if the scope name is defined it should take the custom collection name. If not defined it should go with the default scope and default collection name. Any suggestion on how should this repository be defined?
public interface GlobalLockRepository extends CrudRepository<GlobalLock, String>,GlobalLockCustomRepository {
}
Related
I have the following code:
public interface DummyInterface {
}
and
#Singleton
#Creatable
public class DummyInterfaceImpl1 implements DummyInterface {
}
And when I want I can simply inject this, and it works just fine, (see below):
#Inject
DummyInterfaceImpl1
However I can't do
#Inject
DummyInterface
Because I get an
Unable to process "ClassWhereIInject.dummyInterface": no actual value was found for the argument "DummyInterface".
So, I am trying to understand, if I use the combination of #Creatable and #Singleon, without adding the instance that I want to inject in the IEclipseContext, then I can only inject implementation classes and not interfaces?
I can see how this can get problematic, especially when one has multiple implementation classes for the same interface, and the dependency injection framework doesn't know which to inject...that is if you don't use the #Named annotation to specify...
The injection system only looks for something with the name you specify. It does not try and find a class that happens to implement that interface. So no you can't use an #Creatable class with a different name to the interface.
An alternative is to use a 'ContextFunction'. This is a function which is called when the injection system is looking for a name. The context function can create an instance of something suitable and put it in the context for the injector. Full details on context function are here
I only have two determine the type,one of is my Basic Class, another is generic class name.
BasicOrmDao.class;
Class cls = Class.forName("com.base.Role");
My injection class is
class RoleDao extends BasicOrmDao<Role> {
}
I don't know bean name roleDao, because of it maybe BasicOrmDao.
So how can I get my bean "roleDao" use BasicOrmDao.class and String name = "com.base.Role";.
I want use java code to do this, like #Autowired, but I only known basic type BasicOrmDao, and generic class name "com.base.Role"
I got 2 beans.
The first one is the model I use in production, Model.
#Named("model")
#RequestScoped
public class Model{
}
The second one is the extension of Model that I use for testing.
#Named("modelTest")
#RequestScoped
public class ModelTest extends Model{
}
How can I force CDI to select Model by default?
Since you want to change the 'default' bean for given type and you don't want to use qualifiers, I assume the original bean is not to be injected anywhere. Therefore, what you are probably after is either an alternative or a specialization.
If we talk about alternatives, you need to mark the new bean with #Alternative annotation and also 'select' it - that can be done on a per bean archive basis in beans.xml or simply globally with #Priority(int). Here is a code snippet:
#Named("modelTest")
#RequestScoped
#Alternative
#Priority(1) // "activates"/selects the alternative
public class ModelTest extends Model{
}
With a selected alternative, whenever you inject the previous type (Model), CDI will instead inject this alternative (ModelTest), as it fits the injection point as well.
Secondary option is specialization. It is very similar to alternatives but stricter in a way that the original bean is 'discarded', you can read more about that in CDI spec. Specialization also comes with qualifier and bean name inheritance (not the scope though!). There is also no need to select the bean (as opposed to alternatives). Here is the code:
#RequestScoped
#Specializes
public class ModelTest extends Model{
// bean name with be inherited automatically as "model"
}
Note that a bean can only have one bean name at a time, as per specification. Therefore if you inherit one name and declare another, you will be getting errors - alter your code accordingly.
I am writing repository for variables table and wish to access specific rows with it. For this I am trying to autowire main repository into custom implementation, like this:
public interface VariableRepo extends CrudRepository<Variable, Long>, VariableRepoCustom {
Variable getByName(String name);
}
public interface VariableRepoCustom {
...
Variable getPopulationSingle();
...
}
public class VariableRepoCustomImpl implements VariableRepoCustom {
private final VariableRepo variableRepo;
#Autowired
public VariableRepoCustomImpl(VariableRepo variableRepo) {
this.variableRepo = variableRepo;
}
#Override
public Variable getPopulationSingle() {
return getByName("Population single");
}
...
}
Unfortunately, Spring like to go crazy with this, throwing an exception:
Error creating bean with name 'variableRepo': Invocation of init
method failed; nested exception is
org.springframework.data.mapping.PropertyReferenceException: No
property getPopulationSingle found for type Variable!
I.e. it tries to find repository method inside entity class (Variable) which of course should not contained inside.
How to solve this?
What you named VariableRepoCustom/VariableRepoCustomImpl should be in fact a service (not a repository in terms of spring-data-jpa).
The interface VariableRepoCustom should not be present in JPA searchpath, to prevent JPA to generate an implementation
I think might be your repository impl does not have #Repository annotation. Please make both repository and impl as #Repository. it should fix your problem.
For best practice, No need to autowire VariableRepo interface into impl class.
Edit:
Also remove custom from impl. The name will be RepoName by append impl. it is definition like VariableRepoImpl
I would like to create a Spring Data JPA repository with custom behavior, and implement that custom behavior using Specifications. I have gone through the Spring Data JPA documentation for implementing custom behavior in a single repository to set this up, except there is no example of using a Spring Data Specification from within a custom repository. How would one do this, if even possible?
I do not see a way to inject something into the custom implementation that takes a specification. I thought I would be tricky and inject the CRUD repository portion of the repository into the custom portion, but that results in a circular instantiation dependency.
I am not using QueryDSL. Thanks.
I guess the primary source for inspiration could be how SimpleJpaRepository handles specifications. The key spots to have a look at are:
SimpleJpaRepository.getQuery(…) - it's basically creating a CriteriaQuery and bootstraps a select using a JPA Root. Whether the latter applies to your use case is already up to you. I think the former will apply definitely.
SimpleJpaRepository.applySpecificationToCriteria(…) - it basically uses the artifacts produced in getQuery(…) (i.e. the Root and the CriteriaQuery) and applies the given Specification to exactly these artifacts.
this is not using Specification, so not sure if it's relevant to you, but one way that I was able to inject custom behavior is as follows,
Basic structure: as follows
i. create a generic interface for the set of entity classes which are modeled after a generic parent entity. Note, this is optional. In my case I had a need for this hierarchy, but it's not necessary
public interface GenericRepository<T> {
// add any common methods to your entity hierarchy objects,
// so that you don't have to repeat them in each of the children entities
// since you will be extending from this interface
}
ii. Extend a specific repository from generic (step 1) and JPARepository as
public interface MySpecificEntityRepository extends GenericRepository<MySpecificEntity>, JpaRepository<MySpecificEntity, Long> {
// add all methods based on column names, entity graphs or JPQL that you would like to
// have here in addition to what's offered by JpaRepository
}
iii. Use the above repository in your service implementation class
Now, the Service class may look like this,
public interface GenericService<T extends GenericEntity, ID extends Serializable> {
// add specific methods you want to extend to user
}
The generic implementation class can be as follows,
public abstract class GenericServiceImpl<T extends GenericEntity, J extends JpaRepository<T, Long> & GenericRepository<T>> implements GenericService<T, Long> {
// constructor takes in specific repository
public GenericServiceImpl(J genericRepository) {
// save this to local var
}
// using the above repository, specific methods are programmed
}
specific implementation class can be
public class MySpecificEntityServiceImpl extends GenericServiceImpl<MySpecificEntity, MySpecificEntityRepository> implements MySpecificEntityService {
// the specific repository is autowired
#Autowired
public MySpecificEntityServiceImpl(MySpecificEntityRepository genericRepository) {
super(genericRepository);
this.genericRepository = (MySpecificEntityRepository) genericRepository;
}
}