Micronauts Failed to inject value for parameter [entityManager] of class: UserRepository - entitymanager

I'm trying to inject EntityManager in the repository.
compilation was successful but when i run the application and send a post request i got this error:
Unexpected error occurred: Failed to inject value for parameter [entityManager] of class: aututor.apps.DAO.Repository.RepositoryImp.UserRepository
Message: No bean of type [javax.persistence.EntityManager] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Path Taken: new UserController([UserService service]) --> new UserServiceImpl([IUserRepository userRepository]) --> new UserRepository([EntityManager entityManager])
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [entityManager] of class: aututor.apps.DAO.Repository.RepositoryImp.UserRepository
this is the repository :
package aututor.apps.DAO.Repository.IRepository;
import aututor.apps.DAO.Model.*;
public interface IUserRepository {
public User save(User User);
public User findByEmail(String Email);
}
package aututor.apps.DAO.Repository.RepositoryImp;
import aututor.apps.DAO.Model.User;
import aututor.apps.DAO.Repository.IRepository.IUserRepository;
import io.micronaut.configuration.hibernate.jpa.scope.CurrentSession;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Singleton
public class UserRepository implements IUserRepository {
#PersistenceContext
protected EntityManager entityManager;
public UserRepository(#CurrentSession EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public User save(User User) {
return entityManager.merge(User);
}
#Override
public User findByEmail(String Email) {
return entityManager.createQuery("SELECT user FROM User user WHERE user.Email = :email", User.class)
.setParameter("email", Email)
.getSingleResult();
}
}
this is the service :
package aututor.apps.Services.ServicesImpl;
import aututor.apps.DAO.Model.User;
import aututor.apps.DAO.Repository.IRepository.IUserRepository;
import aututor.apps.DTO.Mapper.UserMapper;
import aututor.apps.DTO.UserDTO;
import aututor.apps.Services.IServices.UserService;
import aututor.apps.Util.Response;
import javax.inject.Singleton;
#Singleton
public class UserServiceImpl implements UserService {
protected final IUserRepository userRepository;
protected final UserMapper userMapper= new UserMapper();
public UserServiceImpl(IUserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public Response CreateUser(UserDTO User) {
if(userRepository.findByEmail(User.getEmail())==null) {
User u = userRepository.save(userMapper.ToUser(User));
return new Response("request has succeeded",userMapper.ToUserDTO(u),200);
}
else {
return new Response("Not Acceptable : Adress email already exist",null,406);
}
}
#Override
public Response UpdateUser(UserDTO User) {
return null;
}
#Override
public Response DeleteUser(UserDTO User) {
return null;
}
#Override
public Response FindUserByID(Long Id) {
return null;
}
}
Controller :
package aututor.apps.Controllers;
import aututor.apps.DTO.UserDTO;
import aututor.apps.Services.IServices.UserService;
import aututor.apps.Util.Response;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.*;
#Controller("/rest/User")
public class UserController {
protected final UserService service ;
public UserController(UserService service) {
this.service = service;
}
#Post("/")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response CreateUser(#Body UserDTO user) {
return service.CreateUser(user);
}
}
build.gradle :
dependencies {
annotationProcessor platform("io.micronaut:micronaut-bom:$micronautVersion")
annotationProcessor "io.micronaut:micronaut-inject-java"
annotationProcessor "io.micronaut:micronaut-validation"
annotationProcessor "io.micronaut.data:micronaut-data-processor:1.0.0"
implementation platform("io.micronaut:micronaut-bom:$micronautVersion")
implementation "io.micronaut:micronaut-security-jwt"
implementation "io.micronaut:micronaut-http-client"
implementation "io.micronaut:micronaut-validation"
implementation "io.micronaut:micronaut-http-server-netty"
implementation "io.micronaut.configuration:micronaut-hibernate-jpa"
implementation("io.micronaut:micronaut-spring")
compile "io.micronaut.configuration:micronaut-jdbc-tomcat"
compile "io.micronaut:micronaut-runtime"
compile "io.micronaut:micronaut-inject"
compile("io.micronaut.data:micronaut-data-hibernate-jpa")
compile("io.micronaut.data:micronaut-data-jdbc")
compile("org.postgresql:postgresql:42.2.1")
runtimeOnly "ch.qos.logback:logback-classic:1.2.3"
testAnnotationProcessor platform("io.micronaut:micronaut-bom:$micronautVersion")
testAnnotationProcessor "io.micronaut:micronaut-inject-java"
testImplementation platform("io.micronaut:micronaut-bom:$micronautVersion")
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "io.micronaut.test:micronaut-test-junit5"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine"
}
application.yml:
---
micronaut:
application:
name: apps
server:
port: 8089
---
datasources:
default:
url: jdbc:postgresql://localhost:5432/db
username: root
password: ''
schema-generate: CREATE_DROP
jpa:
default:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.PostgreSQL95Dialect
entity-scan:
packages: 'apps.model'
i have tried to work with CrudRepository and there was a problem there also. Everything looks correct i don't know if i miss something.

I started working with Micronaut JPA and Hibernate and came across the same kind of issue that you have. Whatever scans the application.yml is not good at all in telling you if you didn't define your jpa settings properly. After getting experience from beating my head over for days trying to get Micronaut to work with data (and on the brink of giving up on using Micronaut from accessing data at all) from looking at your setup, my best bet is you defined your entity-scan packages wrong. If you specify an entity scan package it must be a package that encapsulates or is a parent encapsulating package of your classes that are annotated with #Entity. In your case you specified apps.model as your package, but I see no where in the code you provided where you are referencing anything that follows that package format. Not sure why you have a aututor.apps.DAO.Model.User package. Model should be separate from your DAO. The easiest thing would be to just delete entity-scan packages and let all your classes get scanned. Specifying the package is supposed to improve performance, but if you don't have a lot of files I don't think it really makes a difference. You could have specified aututor or aututor.apps or aututor.apps.DAO or aututor.apps.DAO.Model as your scan package and that should work if your classes with #Entity are in aututor.apps.DAO.Model package.

apply annotation #Repository on your repository class.

Related

A module can not access JpaRepository interface that is in the other module

I am using IntelliJ and Gradle for a sample project. There are two modules.
demo-core module
It has entity and repository classes. build.gradle file is like the below.
apply plugin: 'java'
group 'com.example'
version '0.0.1-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'com.h2database:h2:1.4.200'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.5.3'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}
test {
useJUnitPlatform()
}
I added CustomerRepository class for Customer entity in demo-core module.
package example.springboot.entity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
demo-web module
This is a web module and uses the repository interface like the below.
#SpringBootApplication
public class DemoWebApp {
public static void main(String[] args) {
SpringApplication.run(DemoWebApp.class, args);
}
#Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {
// save a few customers
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));
};
}
}
This is build.gradle file for demo-web module.
plugins {
id 'org.springframework.boot' version '2.5.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group 'com.example'
version '0.0.1-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation project(':demo-core')
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}
test {
useJUnitPlatform()
}
but I can't use JpaRepsitory methods with this error.
/Users/dgkim/Downloads/demo/demo-web/src/main/java/example/springboot/DemoWebApp.java:19: error: cannot access JpaRepository
repository.save(new Customer("Jack", "Bauer"));
^
class file for org.springframework.data.jpa.repository.JpaRepository not found
So, I created a new interface wrapping the CustomerRepository in demo-core module like this.
#Service
public class CustomerFinder {
#Autowired
private CustomerRepository customerRepository;
public Optional<Customer> findCustomer(Long id) {
return customerRepository.findById(id);
}
}
My Controller class uses the wrapper interface like the below.
#RestController
public class CustomerController {
#Autowired
private CustomerFinder finder;
#GetMapping("/customer/{id}")
public String customer(#PathVariable Long id) {
Optional<Customer> customerOptional = finder.findCustomer(id);
if(customerOptional.isPresent()) return "find customer. " + customerOptional.get().getLastName();
else return "no entity";
}
}
It works. JpaRepository methods can be accessed in the same module but demo-web module that has a dependency on demo-core can not access it. DemoWebApp class can access CustomerRepository interface itself but can not access the super interface (JpaRepository).
How can I resolve this issue?
try to change core module dependencies from implementation to api
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.5.3'
to
api 'org.springframework.boot:spring-boot-starter-data-jpa:2.5.3'
You can see the difference between api and implementation here

How to specify collection name while using spring data mongo repository?

I am using spring data to fetch data for my application.
The repository class uses a mongo entity class which is being added as an upstream dependency to my project which means I don't have any control to change the source code of the class. As a result of this, I cannot use #Document annotation from org.springframework.data.mongodb.core.mapping to my mongo entity class.
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface DummyRepository extends MongoRepository<Dummy, String> {
Page<Dummy> findAll(Pageable pageable);
}
Here, I don't have any control over source code of Dummy class so I can't add #Document to specify collection name for this class
How can I specify the collection name while using DummyRepository to query mongo collection?
One way would be to use #EnableMongoRepositories#repositoryFactoryBeanClass with your own flavor of MongoRepsoitoryFactoryBean overriding getEntityInformation(Class).
Unfortunately there's a bug (DATAMONGO-2297) in the code and for the time being you also need to customize getTargetRepsoitory(RepositoryInformation) as shown in the snippet below.
#Configuration
#EnableMongoRepositories(repositoryFactoryBeanClass = CustomRepoFactory.class)
class config extends AbstractMongoConfiguration {
// ...
}
class CustomRepoFactory extends MongoRepositoryFactoryBean {
public CustomRepoFactory(Class repositoryInterface) {
super(repositoryInterface);
}
#Override
protected RepositoryFactorySupport getFactoryInstance(MongoOperations operations) {
return new MongoRepositoryFactory(operations) {
#Override
public <T, ID> MongoEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
return new MappingMongoEntityInformation(
operations.getConverter().getMappingContext().getPersistentEntity(domainClass)) {
#Override
public String getCollectionName() {
return "customize-as-you-wish";
}
};
}
#Override // you should not need this when DATAMONGO-2297 is resolved
protected Object getTargetRepository(RepositoryInformation information) {
MongoEntityInformation<?, Serializable> entityInformation = getEntityInformation(information.getDomainType());
return getTargetRepositoryViaReflection(information, entityInformation, operations);
}
};
}
}

How to log actual target class name for Spring Data Repository when using CustomizableTraceInterceptor

My motivation is to easily find out during maintenance of a large Spring Data Jpa project which Repository method generated given sql.
I have CustomerRepository as in GitHub spring-data-examples.
I changed CustomizableTraceInterceptor to:
public #Bean CustomizableTraceInterceptor interceptor() {
CustomizableTraceInterceptor interceptor = new CustomizableTraceInterceptor();
interceptor.setHideProxyClassNames(true);
interceptor.setEnterMessage("Entering $[targetClassShortName].$[methodName]()");
return interceptor;
}
I would like to see in the log:
Entering CustomerRepository.save()
but instead I am getting:
Entering SimpleJpaRepository.save()
Thanks a lot for your help.
I solved the problem by extending CustomizableTraceInterceptor:
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.interceptor.CustomizableTraceInterceptor;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
public class MethodTraceInterceptor extends CustomizableTraceInterceptor {
#Override
protected Class<?> getClassForLogging(Object target) {
Class<?> classForLogging = super.getClassForLogging(target);
if (SimpleJpaRepository.class.equals(classForLogging)) {
Class<?>[] interfaces = AopProxyUtils.proxiedUserInterfaces(target);
if (interfaces.length > 0) {
return interfaces[0];
}
}
return classForLogging;
}
}
but I find it strange that such overriding is necessary. Ideally Spring trace interceptors should resolve class for logging correctly, even for spring data repositories.

Wildfly throws "Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.QueryParam" error

Im using wildfly 9.0 to deploy my war file. I have java LocalDateTime, Java Money types defined in my REST GET endpoints.
When i deploy my war file, i get following error[1]. Based on this answer [2] I have written "ParamConverterProvider" implementations for both types.
It was working fine( I haven't seen same issue again till now) and now i get same issue.
Any clue?
[1]
Caused by: java.lang.RuntimeException: Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.QueryParam(\"totalMoneyVolumeForPeriod\") on public javax.ws.rs.core.Response com.test.rest.StockEndpoint.getItems(java.lang.Integer,java.lang.Integer,java.lang.String,java.lang.String,java.lang.Long,org.javamoney.moneta.Money,java.util.Set,java.lang.String) for basetype: org.javamoney.moneta.Money"}}}}
[2]
jaxrs could not find my custom (de)serializers for joda.money type
Sample code
package com.test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import javax.money.Monetary;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;
import org.javamoney.moneta.Money;
#Provider
public class MoneyConverterProvider implements ParamConverterProvider {
private final MoneyConverter converter = new MoneyConverter();
#Override
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
if (!rawType.equals(Money.class)) return null;
return (ParamConverter<T>) converter;
}
public class MoneyConverter implements ParamConverter<Money> {
public Money fromString(String value) {
if (value == null ||value.isEmpty()) return null; // change this for production
return Money.of(new BigDecimal(value), Monetary.getCurrency("AUD"));
}
public String toString(Money value) {
if (value == null) return "";
return value.toString(); // change this for production
}
}
}
Application claas
package com.test;
import javax.ws.rs.core.Application;
import com.test.autogen*;
import io.swagger.jaxrs.config.BeanConfig;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
#ApplicationPath("/rest")
public class RestApplication extends Application {
public RestApplication() {
BeanConfig beanConfig = new BeanConfig();
//beanConfig.setVersion("1.0");
beanConfig.setSchemes(new String[] { "http" });
beanConfig.setTitle("My API");
beanConfig.setBasePath("/rest");
beanConfig.setResourcePackage("com.test.autogen");
beanConfig.setScan(true);
}
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>();
set.add(EmailEndpoint.class);
set.add(StockEndpoint.class);
set.add(io.swagger.jaxrs.listing.ApiListingResource.class);
set.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
return set;
}
}
When you are using classpath scanning, JAX-RS components annotated with #Path or #Provider will get picked up and registered. There are a couple way to use classpath scanning. The most common way is to just have an empty Application class annotated with #ApplicationPath
#ApplicationPath("/api")
public class MyApplication extends Application {}
This is enough for a JAX-RS application to be loaded, and to have the application's classpath scanned to components to register.
But, per the specification, once we override any of the Set<Object> getSingletons or Set<Class> getClasses methods of the Application class, and return a non-empty set, this automatically disables classpath scanning, as it is assumed we want to register everything ourselves.
So in previous cases, you were probably just using classpath scanning. In this case, you need to explicitly add the provider to the set of classes in your getClasses method, since you overrode the method to add other component classes.

Injection of #PersistenceContext in CDI-Unit

Here is the unit testing code. When we run unit test code (SampleServiceTest2); EntityManager injected in AbstractDao is always null! How can we inject em during unit test.
*** SampleServiceTest2.java
import javax.inject.Inject;
import org.jglue.cdiunit.CdiRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
#RunWith(CdiRunner.class)
public class SampleServiceTest2 {
#Inject SampleService greeter;
#Test
public void testGreeter() throws Exception {
System.out.println("before2");
greeter.addSampleData(new SampleDataDto(), new KullaniciDto());
System.out.println("after2");
}
}
*** SampleService.java
import javax.ejb.Stateless;
import javax.inject.Inject;
....
#Stateless
#SecuredBean
public class SampleService {
#Inject
SampleLogic sampleLogic;
#Yetki(tag="perm_add_sample_data")
public void addSampleData(SampleDataDto data, KullaniciDto aktifKullaniciDto){
SampleDataHelper sampleDataHelper = new SampleDataHelper();
SampleData sampleData = sampleDataHelper.getEntity(data);
KullaniciHelper kullaniciHelper = new KullaniciHelper();
Kullanici kullanici = kullaniciHelper.getEntity(aktifKullaniciDto);
sampleLogic.addData(sampleData, kullanici);
}
}
**** SampleLogic.java
import javax.inject.Inject;
....
public class SampleLogic {
#Inject
SampleDataDao sampleDataDao;
public void addData(SampleData data, Kullanici kullanici) {
addData1(data,kullanici);
System.out.println("SampleLogic : addData() called!");
}
public void addData1(SampleData data, Kullanici kullanici) {
sampleDataDao.create(data, kullanici);
}
}
**** SampleDataDao.java
public class SampleDataDao extends AbstractDao<SampleData> {
private static final long serialVersionUID = 1L;
}
**** AbstractDao.java
public abstract class AbstractDao<T extends BaseEntity> implements Serializable {
private static final long serialVersionUID = 1L;
#PersistenceContext(unitName="meopdb")
private EntityManager em;
protected EntityManager getEm() {
return em;
}
#SuppressWarnings("rawtypes")
private Class entityClass;
#SuppressWarnings("rawtypes")
private Class getEntityClass() {
if (entityClass == null) {
entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
return entityClass;
}
public T create(T t, Kullanici kullanici) {
if (t.getId() != null) {
throw new IllegalStateException("Create Operation: Oid should be null");
}
t.setId(getSeqNextValue(t));
t.setEklemeZamani(new Timestamp(Calendar.getInstance().getTimeInMillis()));
t.setEkleyenKullaniciId(kullanici.getId());
t.setDurumId(EnumDurum.AKTIF.getValue());
t = em.merge(t);
em.flush();
return t;
}
}
If you test with CDIUnit, the only thing you get is CDI injections, not the full power of Java EE. Injecting entityManager using #PersistenceContext into AbstractDAO is not part of standalone CDI, it is only supported when application is running within a Java EE application server.
The solution is to inject EntityManager using CDI mechanism and create a producer. The producer could be then switched for an alternative in unit tests to provide test entityManager. However, setting up JPA in a standalone unit test is not so straightforward, as you need to specify connection properties directly in persistence.xml file. Also, do not forget to add dependencies on a JPA implementation (hibernate, eclipselink) into your test dependencies.
However, if you do not want to adapt your application's code or you need more than CDI in your tests, you should have a look at Arquillian Java EE test framework.
Here is an example for CDIUnit:
public abstract class AbstractDao<T extends BaseEntity> implements Serializable {
...
#Inject
#Named("meopdb")
private EntityManager em;
...
}
// producer in application - just a wraper over `#PersisteneContext`
public class EntityManagerProducer {
#Produces
#PersistenceContext(unitName="meopdb")
#Named("meopdb")
private EntityManager em;
}
/* producer in your test sources - it creates entityManager via API calls instead of injecting via `#PersistenceContext`. Also, a different persistence unit is used so that it does not clash with main persistence unit, which requires datasource from app server
*/
public TestEntityManagerProducer {
#Produces
#ProducesAlternative // CDIUnit annotation to turn this on as an alternative automatically
#Named("meopdb")
public EntityManager getEm() {
return Persistence
.createEntityManagerFactory("meopdb-test")
.createEntityManager();
}
}
And it is not yet enough. You need to create a new persistence.xml in your test resources with the test persistence unit named "meopdb-test". For this unit you need to specify RESOURCE_LOCAL transaction-type, and specify connection information. And last thing not to forget - you need to list all your entities in the persistence.xml, or in external orm file. This is because your tests run outside of application server. Inside app server, JPA can find entities automatically.
As #OndroMih said, in CDI-Unit, the only thing you get is CDI injections. So you have to cheat a little.
You can use extension do add javax.inject.Inject annnotation to all #PersistenceContext injections
import java.util.Set;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.*;
import javax.inject.Inject;
import javax.persistence.PersistenceContext;
import org.apache.deltaspike.core.util.metadata.AnnotationInstanceProvider;
import org.apache.deltaspike.core.util.metadata.builder.AnnotatedTypeBuilder;
public class AddInjectToPersistenceContextInjectionsCdiExtension implements Extension {
<T> void processAnnotatedType(#Observes ProcessAnnotatedType<T> pat) {
Set<AnnotatedField<? super T>> fields = pat.getAnnotatedType().getFields();
for (AnnotatedField<? super T> field : fields) {
if (shouldInjectionAnnotationBeAddedToField(field)) {
AnnotatedType<T> at = pat.getAnnotatedType();
AnnotatedTypeBuilder<T> builder = new AnnotatedTypeBuilder<T>().readFromType(at);
Inject injectAnnotation = AnnotationInstanceProvider.of(Inject.class);
builder.addToField(field, injectAnnotation);
pat.setAnnotatedType(builder.create());
}
}
}
private <X> boolean shouldInjectionAnnotationBeAddedToField(AnnotatedField<? super X> field) {
return !field.isAnnotationPresent(Inject.class) &&
field.isAnnotationPresent(PersistenceContext.class);
}
}
and produce suitable EntityManager in test class
#RunWith(CdiRunner.class)
#AdditionalClasses(AddInjectToPersistenceContextInjectionsCdiExtension.class)
public class SampleServiceTest2 {
#Inject SampleService greeter;
EntityManagerFactory emf;
#PostConstruct
void init() {
emf = Persistence.createEntityManagerFactory("integration");
}
#Produces
EntityManager createEntityManager() {
return emf.createEntityManager();
}
#Test
public void testGreeter() throws Exception {
}
}
It's not exactly equivalent of what Java EE container does, but it's close enough more often than not.