spring injection issues with spring data - spring

I am getting the following error
Error creating bean with name 'genericRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object
I am new to generics, if there are any generics issue please let me know as well
my Contact.java is in com.merc.template.managelistofobjects.domain package
All other classes are in com.merc.template.managelistofobjects package
ContactCollectionManagerImpl
#Component
public class ContactCollectionManagerImpl extends CollectionManagerImpl<Contact> implements CollectionManager<Contact>{
#Autowired
private GenericRepository<Contact,Long> genericRepository;
public ContactCollectionManagerImpl() {
setGenericRepository(genericRepository);
}
#Override
public void addToCollection(Contact contact, boolean reload){
super.addToCollection(contact, entityDataMap, reload);
}
}
CollectionManagerImpl
public abstract class CollectionManagerImpl<T extends EntityBean> implements CollectionManager<T>{
private GenericRepository objectManager;
public void setGenericRepository(GenericRepository genericRepository) {
this.objectManager = genericRepository;
}
protected void addToCollection(T entity, Map<Long,T> entityDataMap, boolean reload) {
//reload is set to false when the static map needs not be updated
if(reload){
//loads all the existing collection objects from db
loadCollection(entityDataMap, false);
//check if the obect to be inserted already exists in collection
if(entityDataMap.containsKey(entity.getId())){
return;
}
}
//TODO save to database
objectManager.save(entity);
if(reload){
syncCollectionWithDB(entityDataMap);
}
}
}
CollectionManager
public interface CollectionManager<T> {
public void addToCollection(T object, boolean reload);
}
GenericRepository
public interface GenericRepository<T, ID extends Long> extends JpaRepository<T, ID>{
}
MyApplicationContext
#Configuration
#EnableJpaRepositories
#ComponentScan("com.merc.template.managelistofobjects")
#ImportResource("classpath:spring/app-context.xml")
#PropertySource("classpath:application.properties")
public class MyApplicationContext {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
private static final String PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY = "hibernate.ejb.naming_strategy";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
#Resource
private Environment environment;
#Bean
public DataSource dataSource() {
BoneCPDataSource dataSource = new BoneCPDataSource();
dataSource.setDriverClass(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setJdbcUrl(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public JpaTransactionManager transactionManager() throws ClassNotFoundException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
return transactionManager;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws ClassNotFoundException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
//setPackagesToScan = com.merc.template.managelistofobjects.domain
entityManagerFactoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
Properties jpaProterties = new Properties();
jpaProterties.put(PROPERTY_NAME_HIBERNATE_DIALECT, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
jpaProterties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
jpaProterties.put(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY));
jpaProterties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
entityManagerFactoryBean.setJpaProperties(jpaProterties);
return entityManagerFactoryBean;
}
#Bean
public CollectionManager contactCollectionManager(){
return new ContactCollectionManagerImpl();
}
}
My main class contains the following code
ApplicationContext context = new AnnotationConfigApplicationContext(MyApplicationContext.class);
CollectionManager collMgr = context.getBean("contactCollectionManager",CollectionManager.class);
Contact contact = new Contact(2L,"xyz","abc");
collMgr.addToCollection(contact, true);
entitymanager.packages.to.scan=com.merc.template.managelistofobjects.domain
my spring xml file contains just one line
<jpa:repositories base-package="com.merc.template.managelistofobjects"/>
When i run the code I get the following error
java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object

You cannot autowire an object that takes an generic type, You will have to define a strongly typed sub interface of GenericRepository and then autowire it inside your clases
public interface ContactGenericRepository extends GenericRepository<Contact,Long> {}
Then autowire the new interface
#Autowired
private ContactGenericRepository contractGenericRepository;
P.S: you cannot use the autowired object inside the constructor of the class that wrap it, as you are doing inside the ContactCollectionManagerImpl constructor, as the object is not instantiated yet
You could easily use #PostConstruct on any other method that does that behaviour you want, like this
#PostConstruct
public void populateContactCollectionManagerImpl() {
setGenericRepository(genericRepository);
}

Related

Couldn't find PersistentEntity for type class when using #EnableMongoAuditing

I am getting "Couldn't find PersistentEntity for type class" error when I am using #EnableMongoAuditing features along with MongoRepository.
This happens when I save a document when collection isn't already present in database.
I tried whatever is mentioned in:
https://github.com/spring-projects/spring-boot/issues/12023
https://jira.spring.io/browse/DATAMONGO-1999
Spring boot mongodb auditing error
but nothing is working.
Mentioned things are:
Extend MongoConfig by AbstractMongoConfiguration and override all methods.
Here is my code which reproduced the same error:
MongoConfig class
#Configuration
public class MongoConfig extends AbstractMongoConfiguration {
#Value("${spring.data.mongodb.host}")
private String mongoHost;
#Value("${spring.data.mongodb.port}")
private String mongoPort;
#Value("${spring.data.mongodb.database}")
private String mongoDB;
#Override
public MongoDbFactory mongoDbFactory() {
return new SimpleMongoDbFactory(new MongoClient(mongoHost + ":" + mongoPort), mongoDB);
}
#Override
public MongoClient mongoClient() {
return new MongoClient(mongoHost, Integer.parseInt(mongoPort));
}
#Override
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoDbFactory());
}
#Override
public MappingMongoConverter mappingMongoConverter() {
return new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory()), new MongoMappingContext());
}
#Override
protected String getDatabaseName() {
return mongoDB;
}
}
Person Collection class
#Document
public class Person {
#Id
private String id;
private String name;
#CreatedDate
private LocalDateTime createdAt;
#LastModifiedDate
private LocalDateTime lastModified;
// Getter Setters Constructors omitted for brevity
}
Main Application class
#EnableMongoAuditing
#EnableMongoRepositories ({"com.example.*", "org.apache.*"})
#SpringBootApplication
#ComponentScan({"com.example.*", "org.apache.*"})
public class DemoApplication implements CommandLineRunner {
#Autowired
PersonRepository personRepository;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
Person p1 = new Person("1", "prakhar");
personRepository.save(p1);
}
}
Expected Result is Person entity should be saved in database.
Actual Result is "Couldn't find PersistentEntity for type class Person" error
Looks like you ran into https://github.com/spring-projects/spring-boot/issues/12023
Extending AbstractMongoConfiguration will switch off Spring Boot's auto-configuration of various Mongo components and also customises the base packages that are used to scan for mappings. I would recommend that you don't use it in Spring Boot.
Update
I managed to get the example running with the configuration as simple as
#Configuration
public class MongoConfig {
#Value("${spring.data.mongodb.host}")
private String mongoHost;
#Value("${spring.data.mongodb.port}")
private String mongoPort;
#Value("${spring.data.mongodb.database}")
private String mongoDB;
#Bean
public MongoDbFactory mongoDbFactory() {
return new SimpleMongoDbFactory(new MongoClient(mongoHost + ":" + mongoPort), mongoDB);
}
#Bean
public MongoClient mongoClient() {
return new MongoClient(mongoHost, Integer.parseInt(mongoPort));
}
}
and the app class
#EnableMongoAuditing
#SpringBootApplication
public class DemoApplication implements CommandLineRunner {
#Autowired
PersonRepository personRepository;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
Thread.sleep(2000);
Person p1 = new Person("1", "prakhar");
personRepository.save(p1);
}
}
Notice that I followed my own advice and did't inherit from AbstractMongoConfiguration
Explanation
The problem lies in the initialization of
#Bean
public MappingMongoConverter mappingMongoConverter() {
return new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory()), new MongoMappingContext());
}
You simply call MongoMappingContext constructor, without calling setInitialEntitySet. Compare that with MongoDataConfiguration auto-configuration class.
#Bean
#ConditionalOnMissingBean
public MongoMappingContext mongoMappingContext(MongoCustomConversions conversions)
throws ClassNotFoundException {
MongoMappingContext context = new MongoMappingContext();
context.setInitialEntitySet(new EntityScanner(this.applicationContext)
.scan(Document.class, Persistent.class));
Class<?> strategyClass = this.properties.getFieldNamingStrategy();
if (strategyClass != null) {
context.setFieldNamingStrategy(
(FieldNamingStrategy) BeanUtils.instantiateClass(strategyClass));
}
context.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
return context;
}
Even worse, you don't register MongoMappingContext as a managed bean.
Due to this fact, auto-configuration class is still created. This leads to a race condition, I tried to run the original code and could easily reproduce the error, but with a breakpoint in AbstractMappingContext.addPersistentEntity the test always passed.
For me I resolved this issue by adding following method in MongoConfig if your class extends from AbstractMongoConfiguration
#Override
protected String getMappingBasePackage() {
return "com.companyName.modulename"
}
If MongoConfig extends from MongoConfigurationSupport then add below method
#Override
protected Collection<String> getMappingBasePackages() {
return Arrays.asList("com.companyName.module1","com.companyName.module2");
}
Note that in later case I can specify multiple package names as base packages.

Spring Boot - Auto wiring service having String constructor

How do i #autowire bean class TransactionManagerImpl which is having 1(String) argument constructor without using new in spring-boot application?
Even after searching through many post i couldn't get any clue to autowire without using new
I need to autowire TransactionManager in three different classes and the parameters are different in all three classes.
This looks like very basic scenario.
#Service
public class TransactionManagerImpl implements TransactionManager {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
String txnLogFile;
#ConstructorProperties({"txnLogFile"})
public TransactionManagerImpl(String txnLogFile) {
this.txnLogFile= txnLogFile;
}
}
is there any specific requirement where you want to use #Service annotation?
if not then you can use #Bean to create a bean for TransactionManagerImpl like below.
#Configuration
public class Config {
#Value("${txnLogFile}")
private String txnLogFile;
#Bean
public TransactionManager transactionManager() {
return new TransactionManagerImpl(txnLogFile);
}
}
and remove #Service annotation from TransactionManagerImpl.
Putting aside other complications, it can be done like this
public TransactionManagerImpl(#Value("${txnLogFile}") String txnLogFile) {
this.txnLogFile= txnLogFile;
}
Finally, i did it as below, now sure if this is the best way to do. I did not want to have three implementation just because of one variable.
application.yaml
app:
type-a:
txn-log-file: data/type-a-txn-info.csv
type-b:
txn-log-file: data/type-b-txn-info.csv
default:
txn-log-file: data/default/txn-info.csv
MainApplication.java
#SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(MainApplication.class).web(WebApplicationType.NONE).run(args);
}
#Bean
public TransactionManager transactionManager(#Value("${app.default.txn-log-file}") String txnLogFile) {
return new TransactionManagerImpl(txnLogFile);
}
#Bean
public CsvService csvService(String txnLogFile) {
return new CsvServiceImpl(txnLogFile);
}
}
TypeOneRoute.java
#Configuration
public class TypeOneRoute extends RouteBuilder {
#Value("${app.type-a.txn-log-file}")
private String txnLogFile;
#Autowired
private ApplicationContext applicationContext;
private TransactionManager transactionManager;
#Override
public void configure() throws Exception {
transactionManager = applicationContext.getBean(TransactionManager.class, txnLogFile);
transactionManager.someOperation();
}
}
TypeTwoRoute.java
#Configuration
public class TypeTwoRoute extends RouteBuilder {
#Value("${app.type-b.txn-log-file}")
private String txnLogFile;
#Autowired
private ApplicationContext applicationContext;
private TransactionManager transactionManager;
#Override
public void configure() throws Exception {
transactionManager = applicationContext.getBean(TransactionManager.class, txnLogFile);
transactionManager.create();
}
}
TransactionManager.java
#Service
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public interface TransactionManager {
public ZonedDateTime create() throws IOException, ParseException;
}
TransactionManagerImpl.java
public class TransactionManagerImpl implements TransactionManager {
#Autowired
private ApplicationContext applicationContext;
private String txnLogFile;
public TransactionManagerImpl(String txnLogFile) {
this.txnLogFile = txnLogFile;
}
private CsvService csvService;
#PostConstruct
public void init() {
csvService = applicationContext.getBean(CsvService.class, txnLogFile);
}
public ZonedDateTime create() throws IOException, ParseException {
try {
csvService.createTxnInfoFile();
return csvService.getLastSuccessfulTxnTimestamp();
} catch (IOException e) {
throw new IOException("Exception occured in getTxnStartDate()", e);
}
}
}
Initially TransactionManager Bean will be registered with the app.default.txn-info.csv and when i actually get it from ApplicationContext i am replacing the value with the parameter passed to get the bean from ApplicationContext

Null pointer while trying to access Bean

I have a configuration class which creates multiple beans:
#Configuration
public class TopLevelConfig {
#Bean
public MyMapper myMapper() {
MyMapper mapper = new MyMapper();
mapper.registerModule(new MetadataModule());
return new MyMapper();
}
}
Now in MetadataModule:
#Override
public void setupModule(final SetupContext setupContext) {
final SimpleDeserializers deserializers = new SimpleDeserializers();
deserializers.addDeserializer(Payload.class, new PayloadDeserializer());
setupContext.addDeserializers(deserializers);
}
In PayloadDeserializer I'm not able to autowire the MyMapper class. I'm thinking this is because when the new Object of PayloadDeserializer is created, the bean of MyMapper hasn't been created by then. How do I allow PayloadDeserializer to get access to the bean object?
You are creating PayloadDeserializer object by yourself by calling new PayloadDeserializer(), this is the reason why MyMapper is not injected to it. To inject/autowire to work, your bean should be spring managed. To do that, you can use #Component on top of your PayloadDeserializer class like below.
#Component
public class PayloadDeserializer {
private final MyMapper mapper;
#Autowired
public PayloadDeserializer(MyMapper mapper) {
this.mapper = mapper;
}
}
#Configuration
public class TopLevelConfig {
#Bean
public MyMapper myMapper(PayloadDeserializer payloadDeserializer) {
MyMapper mapper = new MyMapper();
mapper.registerModule(metadataModule(payloadDeserializer));
return mapper;
}
#Bean
public MetadataModule metadataModule(PayloadDeserializer payloadDeserializer) {
return new MetadataModule(payloadDeserializer);
}
}
public class MetadataModule {
private final PayloadDeserializer payloadDeserializer;
public MetadataModule(PayloadDeserializer payloadDeserializer) {
this.payloadDeserializer = payloadDeserializer;
}
#Override
public void setupModule(final SetupContext setupContext) {
final SimpleDeserializers deserializers = new SimpleDeserializers();
deserializers.addDeserializer(Payload.class, payloadDeserializer);
setupContext.addDeserializers(deserializers);
}
}

Spring: Cannot autowire beans from parent context

I have a Spring Boot (1.4.0) application, which, during initialization, starts a 2nd context (I need that because I have to publish a web service using a specific kind of authorization while the parent context publishes a different service).
I created a child context like so:
#Configuration
#ConditionalOnClass({Servlet.class, DispatcherServlet.class})
#ConditionalOnWebApplication
public class ChildContextConfiguration implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
private final Logger logger = LoggerFactory.getLogger(ChildContextConfiguration.class);
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private void createChildContext() {
final AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext(ChildConfiguration.class);
childContext.setParent(this.applicationContext);
childContext.setId(this.applicationContext.getId() + ":child");
}
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
logger.info("creating child context");
createChildContext();
}
}
The child context's configuration class looks like this:
#Configuration
#ComponentScan(basePackages = {"com.example.child"})
#PropertySource("file:some-config.properties")
#ConfigurationProperties(prefix = "child")
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class ChildConfiguration {
private Integer port;
private String keyStore;
private String keyStorePass;
private String keyPass;
private String trustStore;
private String trustStorePass;
private String packageBase;
public void setPort(Integer port) {
this.port = port;
}
public void setKeyStore(String keyStore) {
this.keyStore = keyStore;
}
public void setKeyStorePass(String keyStorePass) {
this.keyStorePass = keyStorePass;
}
public void setKeyPass(String keyPass) {
this.keyPass = keyPass;
}
public void setTrustStore(String trustStore) {
this.trustStore = trustStore;
}
public void setTrustStorePass(String trustStorePass) {
this.trustStorePass = trustStorePass;
}
public void setPackageBase(String packageBase) {
this.packageBase = packageBase;
}
#Bean
public Jaxb2Marshaller swpMarshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setPackagesToScan(packageBase);
return marshaller;
}
#Bean
public Unmarshaller swpUnmarshaller() throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(packageBase);
return jaxbContext.createUnmarshaller();
}
#Bean
public Filter encodingFilter() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
return encodingFilter;
}
#Bean
public ServerProperties serverProperties() {
ServerProperties props = new ServerProperties();
props.setPort(port);
props.setSsl(ssl());
return props;
}
private Ssl ssl() {
Ssl ssl = new Ssl();
ssl.setEnabled(true);
ssl.setKeyStore(keyStore);
ssl.setKeyStorePassword(keyStorePass);
ssl.setKeyStoreType("JKS");
ssl.setKeyPassword(keyPass);
ssl.setTrustStore(trustStore);
ssl.setTrustStorePassword(trustStorePass);
ssl.setClientAuth(Ssl.ClientAuth.NEED);
return ssl;
}
}
So far, this works. But when I try to autowire a bean from the parent context, I get an error stating that there is no candidate.
Another interesting thing is, when I inject the (child)context into one of my child context's beans using the ApplicationContextAware interface, the getParent() property of that context is null at that time.
What I have done now is implementing getter functions like these:
private SomeBean getSomeBean() {
if (this.someBean == null) {
this.someBean = applicationContext.getParent().getBean(SomeBean.class);
}
return this.someBean;
}
To summarize this: During construction of the child context's beans, the parent context is not set, so I cannot use autowire.
Is there some way to make autowire work with my setup?
Constructor taking classes to register refreshes context internally - try to set class and refresh manually after setting parent context.
private void createChildContext() {
final AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext();
childContext.setParent(this.applicationContext);
childContext.setId(this.applicationContext.getId() + ":child");
childContext.register(ChildConfiguration.class);
childContext.refresh();
}

How to fix xml-less autowiring of service

When I call a service directly in my main() I can query the database and things work fine. When a jersey request comes in and maps the JSON to NewJobRequest I can't use my service because the #Autowire failed.
My app:
public class Main {
public static final URI BASE_URI = getBaseURI();
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost/").port(9998).build();
}
protected static HttpServer startServer() throws IOException {
ResourceConfig rc = new PackagesResourceConfig("com.production.api.resources");
rc.getFeatures()
.put(JSONConfiguration.FEATURE_POJO_MAPPING, true);
return GrizzlyServerFactory.createHttpServer(BASE_URI, rc);
}
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
//if this is uncommented, it'll successfully query the database
//VendorService vendorService = (VendorService)ctx.getBean("vendorService");
//Vendor vendor = vendorService.findByUUID("asdf");
HttpServer httpServer = startServer();
System.out.println(String.format("Jersey app started with WADL available at " + "%sapplication.wadl\nTry out %shelloworld\nHit enter to stop it...", BASE_URI, BASE_URI));
System.in.read();
httpServer.stop();
}
}
My Resource (controller):
#Component
#Path("/job")
public class JobResource extends GenericResource {
#Path("/new")
#POST
public String New(NewJobRequest request) {
return "done";
}
}
Jersey is mapping the JSON post to:
#Component
public class NewJobRequest {
#Autowired
private VendorService vendorService;
#JsonCreator
public NewJobRequest(Map<String, Object> request) {
//uh oh, can't do anything here because #Autowired failed and vendorService is null
}
}
VendorService:
#Service
public class VendorService extends GenericService<VendorDao> {
public Vendor findByUUID(String uuid) {
Vendor entity = null;
try {
return (Vendor)em.createNamedQuery("Vendor.findByUUID")
.setParameter("UUID", uuid)
.getSingleResult();
} catch (Exception ex) {
return null;
}
}
}
-
#Service
public class GenericService<T extends GenericDao> {
private static Logger logger = Logger.getLogger(Logger.class.getName());
#PersistenceContext(unitName = "unit")
public EntityManager em;
protected T dao;
#Transactional
public void save(T entity) {
dao.save(entity);
}
}
My service config:
#Configuration
public class Config {
#Bean
public VendorService vendorService() {
return new VendorService();
}
}
My config
#Configuration
#ComponentScan(basePackages = {
"com.production.api",
"com.production.api.dao",
"com.production.api.models",
"com.production.api.requests",
"com.production.api.requests.job",
"com.production.api.resources",
"com.production.api.services"
})
#Import({
com.production.api.services.Config.class,
com.production.api.dao.Config.class,
com.production.api.requests.Config.class
})
#PropertySource(value= "classpath:/META-INF/application.properties")
#EnableTransactionManagement
public class Config {
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USER = "db.user";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
#Resource
Environment environment;
#Bean
public DataSource dataSource() {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUrl(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUser(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USER));
dataSource.setPassword(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public JpaTransactionManager transactionManager() throws ClassNotFoundException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
return transactionManager;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws ClassNotFoundException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceUnitName("unit");
entityManagerFactoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
Properties jpaProperties = new Properties();
jpaProperties.put(PROPERTY_NAME_HIBERNATE_DIALECT, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
}
The #Path and #POST annotations are JAX-RS, not Spring. So the container is instantiating your endpoints on its own, without any knowledge of Spring beans. You are most likely not getting any Spring logging because Spring is not being used at all.
I've figured out the issue and blogged about it here: http://blog.benkuhl.com/2013/02/how-to-access-a-service-layer-on-a-jersey-json-object/
In the mean time, I'm also going to post the solution here:
I need to tap into the bean that Spring already created so I used Spring's ApplicationContextAware
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext (ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
And then used that static context reference within my object to be mapped to so I can perform lookups in the service:
public class NewJobRequest {
private VendorService vendorService;
public NewJobRequest() {
vendorService = (VendorService) ApplicationContextProvider.getApplicationContext().getBean("vendorService");
}
#JsonCreator
public NewJobRequest(Map<String, Object> request) {
setVendor(vendorService.findById(request.get("vendorId")); //vendorService is null
}
....
}

Resources