Upgraded to Springboot 2 AbstractRoutingDataSource not working - spring-boot

Hi i was using Spring boot 1.4.0 it was working fine.
When i upgraded to Spring boot 2.0.0 its giving below error.
Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null]
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:305)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:378)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:474)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:289)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.vega.ui.service.SecurityServiceImpl$$EnhancerBySpringCGLIB$$5fdaff4b.getTenantIdByUserName()
Here is my code to implement this
public class TenantContext {
private static ThreadLocal currentTenant = new ThreadLocal<>();
public static void setCurrentTenant(Object tenant) {
System.out.println("tenant : "+tenant);
currentTenant.set(tenant);
}
public static Object getCurrentTenant() {
return currentTenant.get();
}
public static void removeTenant() {
currentTenant.remove();
}
}
public class TenantRoutingDataSource extends AbstractRoutingDataSource {
String tenantId;
private Map<Object, Object> mRountingTargetDataSources;
public void setRountingTargetDataSources(Map<Object, Object> ptargetDataSources) {
mRountingTargetDataSources = ptargetDataSources;
this.setTargetDataSources(ptargetDataSources);
}
public Map<Object, Object> getRountingTargetDataSources() {
return mRountingTargetDataSources;
}
#Override
protected Object determineCurrentLookupKey() {
if (TenantContext.getCurrentTenant() != null)
return TenantContext.getCurrentTenant();
else {
return tenantId;
}
}
}
#Bean(name = "transactionManager")
#Autowired
public DataSourceTransactionManager transactionManager(
#Qualifier("dbTenantDataSource") TenantRoutingDataSource dataSource) {
logger.info("Inside DataSourceTransactionManager");
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
dataSourceTransactionManager.setRollbackOnCommitFailure(true);
return dataSourceTransactionManager;
}

Related

AbstractRoutingDataSource - unable to change datasource dynamically

I am using AbstractRoutingDataSource so as to have multiple data base connections but, even after changing the contextHoler the database remains same
in a single API call it works perfectly fine but if i change the datasource within the same api call it doesn't change the datasource. if i have 2 api calls with different contextHolder it would work
#GetMapping("/getdata2")
public ClaimAmountAndTCD getDetails2() {
ClaimAmountAndTCD claimAmountAndTCD2 = serviceCls.getBook2Data();
System.out.println(claimAmountAndTCD2);
return claimAmountAndTCD2;
}
#GetMapping("/getdata")
public ClaimAmountAndTCD getDetails() {
ClaimAmountAndTCD claimAmountAndTCD = serviceCls.getBook1Data();
// ClaimAmountAndTCD claimAmountAndTCD2 = serviceCls.getBook2Data();
System.out.println(claimAmountAndTCD);
return claimAmountAndTCD;
}
below is my database config code
#Configuration
#Profile("dev")
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "as400EntityManager", transactionManagerRef = "as400TransactionManager", basePackages = {
"com.spring.demo.repository" })
public class DevDataSourceConfig {
#Value("${db.gmrp.sxcd1.servername}")
private String servername;
#Value("${db.gmrp.sxcd1.username}")
private String username;
#Value("${db.gmrp.sxcd1.password}")
private String password;
#Value("${db.gmrp.sxcd1.libraries}")
private String libraries;
#Value("${db.naming}")
private String dbNaming;
#Value("${db.driver}")
private String driver;
#Value("${db.isolation}")
private String dbIsolation;
#Bean
public AS400JDBCDataSource dataSourceDevSXCD1() {
AS400JDBCDataSource as400DataSource = new AS400JDBCDataSource();
System.out.println(driver + " " + libraries + " " + username + " " + password);
as400DataSource.setDriver(driver);
as400DataSource.setLibraries(libraries);
as400DataSource.setServerName(servername);
as400DataSource.setNaming(dbNaming);
as400DataSource.setTransactionIsolation(dbIsolation);
if (password != null && !password.isEmpty() && password.trim().length() > 0) {
as400DataSource.setUser(username);
as400DataSource.setPassword(password);
}
return as400DataSource;
}
#Bean(name = "as400dev")
#Primary
public DataSource dataSource() {
AbstractRoutingDataSource dataSource = new RoutingDataSource();
Map<Object, Object> resolvedDataSources = new HashMap<>();
resolvedDataSources.put(DbType.DEVSXCD1, dataSourceDevSXCD1());
dataSource.setDefaultTargetDataSource(dataSourceDevSXCD1()); // default
dataSource.setTargetDataSources(resolvedDataSources);
return dataSource;
}
#Bean(name = "as400EntityManager")
#Primary
public LocalContainerEntityManagerFactoryBean as400DevEntityManager(EntityManagerFactoryBuilder builder,
#Qualifier("as400dev") DataSource as400DataSource) {
return builder.dataSource(as400DataSource).packages("com.spring.demo.entity").build();
}
#Bean(name = "as400TransactionManager")
public PlatformTransactionManager as400DevTransactionManager(
#Qualifier("as400EntityManager") EntityManagerFactory entityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManager);
return transactionManager;
}
}
DbContextHoler class
package com.spring.demo.config;
public final class DbContextHolder {
private DbContextHolder() {
// default constructor
}
private static final ThreadLocal<DbType> contextHolder = new ThreadLocal<>();
// set the data source
public static void setDbType(DbType dbType) {
if (dbType == null) {
throw new NullPointerException();
}
contextHolder.set(dbType);
}
// get the current data source in use
public static DbType getDbType() {
return contextHolder.get();
}
// clear data source
public static void clearDbType() {
contextHolder.remove();
}
}
AbstractRoutingDataSource
package com.spring.demo.config;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class RoutingDataSource extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}

unable run Quartz JDBCJobStore with AbstractRoutingDataSource

I have implemented the application using Spring RoutingDataSource.
Spring -> DS1,
DS2
Based on the logged in URL I am changing the Data Source. it is working fine.
Coming to the quartz, I am unable to change the data source dynamically. Always jobs are getting scheduled on default data source.
#Configuration
public class SchedulerConfig {
#Autowired
private DataSource dataSource;
#Autowired
private QuartzProperties quartzProperties;
#Bean
public JobFactory jobFactory(ApplicationContext applicationContext) {
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
#Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) {
Properties properties = new Properties();
properties.putAll(quartzProperties.getProperties());
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobFactory(jobFactory);
factory.setDataSource(dataSource);
factory.setGlobalJobListeners(jobListener());
factory.setQuartzProperties(properties);
return factory;
}
#Bean
public JobListenerSupport jobListener() {
return new JobListener();
}
}
Data Source Routing Configuration::
#Component
public class DataSourceRouting extends AbstractRoutingDataSource {
private DataSourceOneConfig dataSourceOneConfig;
private DataSourceTwoConfig dataSourceTwoConfig;
private DataSourceContextHolder dataSourceContextHolder;
public DataSourceRouting(DataSourceContextHolder dataSourceContextHolder, DataSourceOneConfig dataSourceOneConfig,
DataSourceTwoConfig dataSourceTwoConfig) {
this.dataSourceOneConfig = dataSourceOneConfig;
this.dataSourceTwoConfig = dataSourceTwoConfig;
this.dataSourceContextHolder = dataSourceContextHolder;
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(DataSourceEnum.tenant1, dataSourceOneDataSource());
dataSourceMap.put(DataSourceEnum.tenant2, dataSourceTwoDataSource());
this.setTargetDataSources(dataSourceMap);
this.setDefaultTargetDataSource(dataSourceTwoDataSource());
}
#Override
protected Object determineCurrentLookupKey() {
return dataSourceContextHolder.getBranchContext();
}
public DataSource dataSourceOneDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(dataSourceOneConfig.getUrl());
dataSource.setUsername(dataSourceOneConfig.getUsername());
dataSource.setPassword(dataSourceOneConfig.getPassword());
return dataSource;
}
public DataSource dataSourceTwoDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(dataSourceTwoConfig.getUrl());
dataSource.setUsername(dataSourceTwoConfig.getUsername());
dataSource.setPassword(dataSourceTwoConfig.getPassword());
return dataSource;
}
}
Data Soruce Config ::
#RequiredArgsConstructor
#DependsOn("dataSourceRouting")
public class DataSourceConfig {
private final DataSourceRouting dataSourceRouting;
#Bean
#Primary
public DataSource dataSource() {
return dataSourceRouting;
}
#Bean(name = "entityManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dataSource()).packages("com.model.entity").build();
}
#Bean(name = "transcationManager")
public JpaTransactionManager transactionManager(
#Autowired #Qualifier("entityManager") LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
return new JpaTransactionManager(entityManagerFactoryBean.getObject());
}
}

Implementing Snapshot in AXON 3.0 : Aggregate Type is unknown in this snapShotter

I'm still new to the axon frame work.
I'm trying to implement snapshotting using mongodb in my application and I keep on getting an error saying
"AbstractSnapshotter : An attempt to create and store a snapshot resulted in an exception. Exception summary: Aggregate Type is unknown in this snapshotter: com.myworklife.contacts.domain.contact.Contact"
This is a part of my java config file.
#Bean
public AggregateSnapshotter snapShotter(EventStore eventStore, AggregateFactory<Contact> contactAggregateFactory) {
return new AggregateSnapshotter(eventStore);
}
#Bean
public SnapshotTriggerDefinition snapshotTriggerDefinition(Snapshotter snapShotter) throws Exception {
return new EventCountSnapshotTriggerDefinition(snapShotter, 1);
}
#Bean
public EventStore eventStore(EventStorageEngine eventStorageEngine) {
return new EmbeddedEventStore(eventStorageEngine);
}
#Bean
public Repository<Contact> contactAggregateRepository(EventStore eventStore, SnapshotTriggerDefinition snapshotTriggerDefinition) {
return new ContactRepository(eventStore, snapshotTriggerDefinition);
}
And my repository.
#Repository("ContactRepository")
public class ContactRepository extends EventSourcingRepository<Contact> {
#Autowired
public ContactRepository(EventStore eventStore, SnapshotTriggerDefinition snapshotTriggerDefinition) {
super(Contact.class, eventStore, snapshotTriggerDefinition);
}
public Contact findContact(ContactId contactId) {
return load(contactId.toString()).getWrappedAggregate().getAggregateRoot();
}
}
My aggregate.
#Aggregate(repository="contactAggregateRepository")
public class Contact {
#AggregateIdentifier
private ContactId id;
private String name;
private String mobileNumber;
public Contact() {
// do nothing, Axon requires default constructor
}
#CommandHandler
public Contact(CreateContactCommand createContactCommand) {
apply(new ContactHasBeenCreatedEvent(createContactCommand.getContactId(), createContactCommand.getName(),
createContactCommand.getMobileNumber()));
}
}
Is there something I'm doing wrong?
since I'm getting an error saying "An attempt to create and store a snapshot resulted in an exception. Exception summary: Aggregate Type is unknown in this snapshotter: com.myworklife.contacts.domain.contact.Contact"
Any help will be highly appreciated.
Thanks,
Pat
You need to add the contactAggregateFactory to the constructor of the AggregateSnapshotter in the snapShotter bean:
#Bean
public AggregateSnapshotter snapShotter(EventStore eventStore, AggregateFactory<Contact> contactAggregateFactory) {
return new AggregateSnapshotter(eventStore, contactAggregateFactory);
}
1.depencity jar
<dependency>
<groupId>org.axonframework</groupId>
<artifactId>axon-spring-boot-autoconfigure</artifactId>
<version>${axon.version}</version>
</dependency>
2.At first,you should config your application.ymp or bootstrap.yml,like this:spring:
data:
mongodb:
host: localhost
port: 27017
database: axonframework
events: domainevents
snapshots: snapshotevents
3.config your mongoDB:
#Bean(name = "axonMongoTemplate")
public MongoTemplate axonMongoTemplate() {
MongoTemplate template = new DefaultMongoTemplate(mongoClient(), mongoDbName, eventsCollectionName, snapshotCollectionName);
return template;
}
#Bean
public MongoClient mongoClient(){
MongoFactory mongoFactory = new MongoFactory();
mongoFactory.setMongoAddresses(Arrays.asList(new ServerAddress(mongoHost)));
return mongoFactory.createMongo();
}
#Bean
public EventStorageEngine eventStorageEngine(Serializer serializer){
return new MongoEventStorageEngine(
serializer,null, axonMongoTemplate(), new DocumentPerEventStorageStrategy());
4.config repository for your aggregate,for example,i config a Element Aggreaget's repository
#Configuration
public class ElementConfiguration {
#Autowired
private EventStore eventStore;
#Bean
#Scope("prototype")
public Element elementAggregate() {
return new Element();
}
#Bean
public AggregateFactory<Element> elementAggregateAggregateFactory() {
SpringPrototypeAggregateFactory<Element> aggregateFactory = new SpringPrototypeAggregateFactory<>();
aggregateFactory.setPrototypeBeanName("elementAggregate");
return aggregateFactory;
}
#Bean
public SpringAggregateSnapshotterFactoryBean springAggregateSnapshotterFactoryBean(){
SpringAggregateSnapshotterFactoryBean factory = new SpringAggregateSnapshotterFactoryBean();
return factory;
}
#Bean
public Repository<Element> elementAggregateRepository(Snapshotter snapshotter) {
EventCountSnapshotTriggerDefinition eventCountSnapshotTriggerDefinition = new EventCountSnapshotTriggerDefinition(snapshotter, 3);
EventSourcingRepository<Element> repository = new EventSourcingRepository<Element>(
elementAggregateAggregateFactory(),
eventStore,
eventCountSnapshotTriggerDefinition
);
return repository;
}
5.enjoy
If you're using Axon 3.3 and SpringBoot 2, this is how we did it in this project:
#Configuration
public class SnapshotConfiguration {
#Bean
public SpringAggregateSnapshotter snapshotter(ParameterResolverFactory parameterResolverFactory,
EventStore eventStore,
TransactionManager transactionManager) {
// https://docs.axoniq.io/reference-guide/v/3.3/part-iii-infrastructure-components/repository-and-event-store#snapshotting
// (...) By default, snapshots are created in the thread that calls the scheduleSnapshot() method, which is generally not recommended for production (...)
Executor executor = Executors.newSingleThreadExecutor();
return new SpringAggregateSnapshotter(eventStore, parameterResolverFactory, executor, transactionManager);
}
#Bean
public EventCountSnapshotTriggerDefinition snapshotTrigger(SpringAggregateSnapshotter snapshotter) {
int snapshotThreshold = 42;
return new EventCountSnapshotTriggerDefinition(snapshotter, snapshotThreshold);
}
}
And if you need the EventStore configuration:
#Configuration
public class AxonMongoEventStoreConfiguration {
#Bean
public MongoClient axonMongoClient(MongoClientURI axonMongoClientUri) {
return new MongoClient(axonMongoClientUri);
}
#Bean
public MongoClientURI axonMongoClientUri() {
return new MongoClientURI("mongodb://host:port/database");
}
#Bean
#Primary
public EventStorageEngine eventStore(MongoClient axonMongoClient, MongoClientURI axonMongoClientUri) {
DefaultMongoTemplate mongoTemplate = new DefaultMongoTemplate(axonMongoClient, axonMongoClientUri.getDatabase());
return new MongoEventStorageEngine(mongoTemplate);
}
}

Integrate my app with Activiti

I have one issue. I integrate my app with Activiti (in the same DB). When I insert, update or delete my entities (not entities's Activiti) by Dao class have use #Transactional but nothing about is being saved to database with no exception.
Here is my config to integrating:
#Configuration
public class ActivitiEngineConfiguration {
private final Logger log = LoggerFactory.getLogger(ActivitiEngineConfiguration.class);
#Autowired
protected Environment environment;
#Bean
public DataSource dataSource() {
SimpleDriverDataSource ds = new SimpleDriverDataSource();
try {
#SuppressWarnings("unchecked")
Class<? extends Driver> driverClass = (Class<? extends Driver>) Class.forName(environment.getProperty("jdbc.driver", "org.postgresql.Driver"));
ds.setDriverClass(driverClass);
} catch (Exception e) {
log.error("Error loading driver class", e);
}
ds.setUrl(environment.getProperty("spring.datasource.url"));
ds.setUsername(environment.getProperty("spring.datasource.username"));
ds.setPassword(environment.getProperty("spring.datasource.password"));
return ds;
}
#Bean(name = "transactionManager")
public PlatformTransactionManager annotationDrivenTransactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
System.out.println("transactionManager: "+transactionManager);
return transactionManager;
}
#Bean(name="processEngineFactoryBean")
public ProcessEngineFactoryBean processEngineFactoryBean() {
ProcessEngineFactoryBean factoryBean = new ProcessEngineFactoryBean();
factoryBean.setProcessEngineConfiguration(processEngineConfiguration());
return factoryBean;
}
#Bean(name="processEngine")
public ProcessEngine processEngine() {
// Safe to call the getObject() on the #Bean annotated processEngineFactoryBean(), will be
// the fully initialized object instanced from the factory and will NOT be created more than once
try {
return processEngineFactoryBean().getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Bean(name="processEngineConfiguration")
public ProcessEngineConfigurationImpl processEngineConfiguration() {
SpringProcessEngineConfiguration processEngineConfiguration = new SpringProcessEngineConfiguration();
processEngineConfiguration.setDataSource(dataSource());
processEngineConfiguration.setDatabaseSchemaUpdate(environment.getProperty("engine.schema.update", "true"));
processEngineConfiguration.setTransactionManager(annotationDrivenTransactionManager());
processEngineConfiguration.setJobExecutorActivate(Boolean.valueOf(
environment.getProperty("engine.activate.jobexecutor", "false")));
processEngineConfiguration.setAsyncExecutorEnabled(Boolean.valueOf(
environment.getProperty("engine.asyncexecutor.enabled", "true")));
processEngineConfiguration.setAsyncExecutorActivate(Boolean.valueOf(
environment.getProperty("engine.asyncexecutor.activate", "true")));
processEngineConfiguration.setHistory(environment.getProperty("engine.history.level", "full"));
String mailEnabled = environment.getProperty("engine.email.enabled");
if ("true".equals(mailEnabled)) {
processEngineConfiguration.setMailServerHost(environment.getProperty("engine.email.host"));
int emailPort = 1025;
String emailPortProperty = environment.getProperty("engine.email.port");
if (StringUtils.isNotEmpty(emailPortProperty)) {
emailPort = Integer.valueOf(emailPortProperty);
}
processEngineConfiguration.setMailServerPort(emailPort);
String emailUsernameProperty = environment.getProperty("engine.email.username");
if (StringUtils.isNotEmpty(emailUsernameProperty)) {
processEngineConfiguration.setMailServerUsername(emailUsernameProperty);
}
String emailPasswordProperty = environment.getProperty("engine.email.password");
if (StringUtils.isNotEmpty(emailPasswordProperty)) {
processEngineConfiguration.setMailServerPassword(emailPasswordProperty);
}
}
// List<AbstractFormType> formTypes = new ArrayList<AbstractFormType>();
// formTypes.add(new UserFormType());
// formTypes.add(new ProcessDefinitionFormType());
// formTypes.add(new MonthFormType());
// processEngineConfiguration.setCustomFormTypes(formTypes);
return processEngineConfiguration;
}
#Bean
public RepositoryService repositoryService() {
return processEngine().getRepositoryService();
}
#Bean
public RuntimeService runtimeService() {
return processEngine().getRuntimeService();
}
#Bean
public TaskService taskService() {
return processEngine().getTaskService();
}
#Bean
public HistoryService historyService() {
return processEngine().getHistoryService();
}
#Bean
public FormService formService() {
return processEngine().getFormService();
}
#Bean
public IdentityService identityService() {
return processEngine().getIdentityService();
}
#Bean
public ManagementService managementService() {
return processEngine().getManagementService();
}
}
DAO Layer:
#Autowired
private SessionFactory sessionFactory;
#Override
#Transactional
public void save(MyEntity obj) {
sessionFactory.getCurrentSession().saveOrUpdate(loaiDanhMuc);
}
Thank all!
I guess #Transactional is not working in this case
Please check following things below:
Check if <tx:annotation-driven /> is defined in your spring xml file.

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