How can I create beans from properties at runtime with autowiring capability - spring

I try to create beans at runtime from application.ymal like this
config:
properties:
service1:
propertyService1: valueService1
service2:
propertyService2: valueService2
The class in which the bean was created...
#Configuration
public class DynamicBeanConfiguration implements ApplicationContextAware {
private TestProperties testProperties;
public DynamicBeanConfiguration(TestProperties testProperties) {
this.testProperties = testProperties;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
for (Map.Entry<String, Properties> entry: testProperties.getProperties().entrySet()) {
String beanName = entry.getKey();
ConfigurableListableBeanFactory beanFactory = configurableApplicationContext.getBeanFactory();
TestDynamicBean dynamicBean = (TestDynamicBean) beanFactory.createBean(TestDynamicBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
for (Map.Entry<Object, Object> properties: entry.getValue().entrySet()) {
dynamicBean.setServiceName(beanName);
dynamicBean.setValue(properties.getValue().toString());
beanFactory.autowireBean(dynamicBean);
beanFactory.registerSingleton(beanName, dynamicBean);
}
}
}
}
The class in which autoconfiguration was created...
#Configuration
#EnableConfigurationProperties(TestProperties.class)
public class TestAutoConfiguration {
#Bean
public DynamicBeanConfiguration dynamicBeanConfiguration(TestProperties properties) {
return new DynamicBeanConfiguration(properties);
}
}
And in this way I successfully get the created beans...
TestDynamicBean service2 = applicationContext.getBean("service2", TestDynamicBean.class);
TestDynamicBean service1 = applicationContext.getBean("service1", TestDynamicBean.class);
But I can't understand how can I use these beans via #Autowired with #Qualifier?
If I create beans this way, no beandefinition is created...
if I created beans through BeanDefinitionRegistryPostProcessor, then it is not possible to read the properties in the map...
Of course I can still return the map this way...
#Bean
public Map<String, TestDynamicBean> dynamicBeanConfiguration(TestProperties properties) {
return new DynamicBeanConfiguration(properties);
But I would like to call services like this...
#Autowired(required = false)
#Qualifier("service1")
private TestDynamicBean service1;
Thanks for any ideas.

Got almost what I wanted...
#Autowired
private DynamicBeanConfiguration dynamicBeanMap;
#Autowired(required = false)
#Qualifier("service1")
private TestDynamicBean service1;
#Autowired(required = false)
#Qualifier("service2")
private TestDynamicBean service2;

Related

How to get the Bean package from ConfigurableApplicationContext

Using a interface like ConfigurableApplicationContext, it is possible to retrieve the list of Beans running in the Spring DI container, but I would like to know what Beans come from the User Space and what Beans comes from the Spring Boot / Spring Boot Starters.
#TestConfiguration
static class BeanInventoryConfiguration {
#Autowired
private ConfigurableApplicationContext applicationContext;
record BeanInventory(List<String> beans) {}
#Bean
public BeanInventory getBeanInventory(ConfigurableApplicationContext applicationContext) {
String[] allBeanNames = applicationContext.getBeanDefinitionNames();
return new BeanInventory(Arrays.stream(allBeanNames).toList());
}
}
Does exist a way to return the package where the Bean is located?
If I know the package, I could filter in a easy way.
Reviewing the Javadoc from Spring, I didnt find a way:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ConfigurableApplicationContext.html
Many thanks in advance
POC: https://github.com/jabrena/spring-boot-http-client-poc/blob/main/src/test/java/ms/info/ms/BeanInventoryTests.java
I found a solution for it:
#TestConfiguration
public class BeanInventory {
#Autowired
private ConfigurableApplicationContext applicationContext;
public record BeanInfo(String name, String pkg) {}
private final List<BeanInfo> beans = new ArrayList<>();
#PostConstruct
private void after() {
final String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanNames) {
final Object beanObject = applicationContext.getBean(beanName);
Class<?> targetClass = AopUtils.getTargetClass(beanObject);
if (AopUtils.isJdkDynamicProxy(beanObject)) {
Class<?>[] proxiedInterfaces = AopProxyUtils.proxiedUserInterfaces(beanObject);
Assert.isTrue(proxiedInterfaces.length == 1, "Only one proxied interface expected");
targetClass = proxiedInterfaces[0];
}
beans.add(new BeanInfo(beanName, targetClass.getPackageName()));
}
}
public List<BeanInfo> getBeans() {
return beans;
}
}
Further information here:
https://github.com/spring-projects/spring-framework/issues/29973#event-8527246281
Note: Many thanks to Simon Basle

Spring Batch : How to change the default isolation level?

I read in the documentation :
"The default is ISOLATION_SERIALIZABLE, which prevents accidental
concurrent execution of the SAME job"
However, when I launch DIFFERENT jobs at the the same time (with a default isolation level at SERIALIZABLE), I have the error : ORA-08177: can't serialize access for this transaction. Is it normal ?
Second, to change the Default Isolation Level to READ_COMMITTED, I understood that we can't change this level in application.properties, and, that I have to redefine BatchConfigurer. Exact ?
Using BasicBatchConfigurer, I must define an explicit contructor (implicit super constructor BasicBatchConfigurer() is undefined for default constructor).
However, I have the error :
Parameter 0 of constructor in MyBatchConfigurer required a bean of type 'org.springframework.boot.autoconfigure.batch.BatchProperties' that could not be found.
How to create : BatchProperties properties, DataSource dataSource and TransactionManagerCustomizers transactionManagerCustomizers ?
This is my code :
PeopleApplication.java
#SpringBootApplication
#EnableAutoConfiguration(exclude = { BatchAutoConfiguration.class })
public class PeopleApplication {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(PeopleApplication.class)
.web(WebApplicationType.NONE)
.run(args);
int exitValue = SpringApplication.exit(ctx);
System.exit(exitValue);
}
}
MyBatchConfigurer.java
#Component
#PropertySource("classpath:fileA.properties")
public class MyBatchConfigurer extends BasicBatchConfigurer implements CommandLineRunner, ExitCodeGenerator {
protected MyBatchConfigurer(BatchProperties properties, DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers) {
super(properties, dataSource, transactionManagerCustomizers);
}
#Override
protected String determineIsolationLevel() {
return "ISOLATION_" + Isolation.READ_COMMITTED;
}
#Override
public void run(String... args) {
...
}
...
}
Regards.
RESPONSE :
use #EnableAutoConfiguration instead of :
#EnableAutoConfiguration(exclude = { BatchAutoConfiguration.class })
Like this, the bean BatchProperties, DataSource and TransactionManagerCustomizers will be automatically created.
Please see the reply from Mahmoud that explains very clearly
can't serialize access for this transaction in spring batch.
Example for the usage is below and override only isolation level
--application.properties
spring.application.name=SpringBatch
####### SPRING ##############
spring.main.banner-mode=off
spring.main.web-application-type=none
spring.batch.initialize-schema=always
spring.batch.job.enabled=false // Disable default if you want to control
########JDBC Datasource########
#connection timeout 10 min
spring.datasource.hikari.connection-timeout=600000
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=100
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.poolName=SpringBoot-HikariCP
spring.datasource.url=jdbc:oracle:thin:#ngecom.ae:1521:ngbilling
spring.datasource.username=ngbilling
springbatch.datasource.password=ngbilling
#SpringBootApplication
public class YourApplication {
public static void main(String[] args) {
SpringApplication.run(SsadapterApplication.class, args);
}
}
// Your manual batch scheduler
class BatchJobScheduler extends BasicBatchConfigurer {
#Autowired
private JobLauncher jobLauncher;
#Autowired
private ApplicationArguments args;
#Autowired
private Job myJob;
protected BatchJobScheduler(BatchProperties properties, DataSource dataSource,
TransactionManagerCustomizers transactionManagerCustomizers) {
super(properties, dataSource, transactionManagerCustomizers);
}
#Override
protected String determineIsolationLevel() {
return "ISOLATION_" + Isolation.READ_COMMITTED;
}
//#Scheduled(cron = "${batch.cron}")
public void notScheduledJob() {
appId= args.getOptionValues("appId").get(0);
JobParameters params = new JobParametersBuilder().addLong("jobId"+appId, System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(myJob, params);
}
// Your batch Configuration And Spring will do everything for you to available
#Configuration
#EnableBatchProcessing
#EnableScheduling
public class BatchConfiguration {
Logger logger = LoggerFactory.getLogger(BatchConfiguration.class);
#Value("${batch.commit.chunk}")
private Integer chunkSize;
#Value("${batch.error.skipCount}")
private Integer skipErrorCount;
#Autowired
private Environment environment;
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Autowired
private DataSource dataSource;
#Autowired
private ApplicationArguments args;
#Autowired
private JdbcTemplate jdbcTemplate;
#Bean
public Job myJob() throws Exception {
return jobBuilderFactory.get("myJob").incrementer(new RunIdIncrementer())
.listener(new JobListener()).start(myStep()).build();
}
#Bean
public Step myStep() throws Exception {
return stepBuilderFactory.get("myStep").<InputObject, OutPutObject>chunk(chunkSize)
.reader(yourReader(null)).processor(yourProcessor()).writer(yourWriter())
//.faultTolerant()
//.skipLimit(skipErrorCount).skip(Exception.class)//.noSkip(FileNotFoundException.class)
.listener(invoiceSkipListener())
//.noRetry(Exception.class)
//.noRollback(Exception.class)
.build();
}

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

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