Spring batch app does not process all items - spring

I have a spring batch app which is weird that I dont know why does not process all items ,I am using range partition and compositeprocessor for the data transform. If my reader reads 5787 records for example, it is an example because they can be more, it only processes 5704 recors and the rest remain unprocessed. I hope someone can help me , thanks in advance.
My dataitemprocessor
public class data implements ItemProcessor<beangenerico,ThreadLocal<List<beanAccountCollect>>> {
Logger logger = Logger.getLogger(data.class);
private String SP_SQL = "{call GetDetailAccount(?)}";
private String SELECT = "{call myspbyblocks (?,?)}";
private beanAccountCollect b;
private ThreadLocal<List<beanAccountCollect>> listbeanAccC = new ThreadLocal<List<beanAccountCollect>>();
private ThreadLocal<List<beanCustomer>> listbeanc=new ThreadLocal<List<beanCustomer>>();
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public ThreadLocal<List<beanAccountCollect>> process(beangenerico rangos) {
// TODO Auto-generated method stub
listbeanAccC.set(new ArrayList<beanAccountCollect>());
try {
listbeanc = this.jdbcTemplate.query(SELECT,new Object [] {rangos.getIni(),rangos.getFin()},new CustomerResultSetExtractor());
for(beanCustomer bc : listbeanc.get()) {
b = new beanAccountCollect();
b.setUsernetwork(bc.getUsernetwork());
b.setTipoagente(bc.getTipoagente());
b.setLbpar(this.jdbcTemplate.query(SP_SQL,new Object [] {bc.getCuenta()},new BeanAccountResulSetExtractor(this.jdbcTemplate)));
listbeanAccC.get().add(b);
}
}catch (Exception e) {
logger.error(e);
}
return listbeanAccC;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
This is my transform data
public class transformDataWS implements ItemProcessor<ThreadLocal<List<beanAccountCollect>>, ThreadLocal<List<beanNewMessageBeanP>>>
{
Logger logger = Logger.getLogger(transformDataWS.class);
private ThreadLocal<List<beanNewMessageBeanP>> lstbnmbp = new ThreadLocal<List<beanNewMessageBeanP>>();
private beanNewMessageBeanP bnmbp;
public ThreadLocal<List<beanNewMessageBeanP>> process(ThreadLocal<List<beanAccountCollect>> list) throws Exception {
// TODO Auto-generated method stub
lstbnmbp.set(new ArrayList<beanNewMessageBeanP>());
List<beanParameter> lbeanPar=null;
List<NMessagePEntryBeanParray> lNMPEBa = null;
for(beanAccountCollect bc:list.get()) {
NewMessageParametrosEntryBeanP nb = new NewMessageParametrosEntryBeanP();
NMessagePEntryBeanParray bar= null;
NewMessageParametrosEntryBeanP [] ba = null;
lNMPEBa = new ArrayList<NMessagePEntryBeanParray>();
lbeanPar = new ArrayList<beanParameter>();
lbeanPar = bc.getLbpar();
bnmbp = new beanNewMessageBeanP();
bnmbp.setTipoagente(bc.getTipoagente());
bnmbp.setUsernetwork(bc.getUsernetwork());
if(lbeanPar!=null) {
for(beanParameter bpar : lbeanPar) {
ba = new NewMessageParametrosEntryBeanP[54];
bar = new NMessagePEntryBeanParray();
ba[0] = new NewMessageParametrosEntryBeanP();
ba[0].setKey("PaymentQ");
ba[0].setValue(bpar.getPQ());
ba[1] = new NewMessageParametrosEntryBeanP();
ba[1].setKey("PaymentReest");
ba[1].setValue(bpar.getPR());
ba[2] = new NewMessageParametrosEntryBeanP();
ba[2].setKey("DelayCte");
ba[2].setValue(bpar.getDelayCte());
ba[3] = new NewMessageParametrosEntryBeanP();
ba[3].setKey("DelayRange");ba[3].setValue(bpar.getDelayR());
ba[4] = new NewMessageParametrosEntryBeanP();
ba[4].setKey("C4");ba[4].setValue(bpar.getC3());
ba[5] = new NewMessageParametrosEntryBeanP();
ba[5].setKey("C6");ba[5].setValue(bpar.getC6());
ba[6] = new NewMessageParametrosEntryBeanP();
ba[6].setKey("Banddict");ba[6].setValue(bpar.getBanddict());
ba[7] = new NewMessageParametrosEntryBeanP();
ba[7].setKey("Street");ba[7].setValue(bpar.getStreet());
ba[8] = new NewMessageParametrosEntryBeanP();
ba[8].setKey("Stree_1");ba[8].setValue(bpar.getStreet1());
//....
ba[53] = new NewMessageParametrosEntryBeanP();
ba[53].setKey("Zone");ba[53].setValue(bpar.getZone());
bar.setArr(ba);
lNMPEBa.add(bar);
}
}
bnmbp.setNmespebarr(lNMPEBa);
lstbnmbp.get().add(bnmbp);
}
return lstbnmbp;
}
}
This is my config job
#EnableBatchProcessing
#Configuration
#Import({DBConfiguration.class})
#ComponentScan({"com.mycompany.batch.config","com.mycompany.batch.mapper","com.mycompany.batch.model","com.mycompany.batch.particion","com.mycompan.batch.procesos","com.mycompany.batch.reader","com.mycompany.batch.writers"})
#PropertySource("file:pruebas.properties")
public class ConfigJobBatch {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
#Qualifier("sqlserverDataSource")
private DataSource dataSource;
#Autowired
Environment envws;
#Bean(name = "demoPartitionStep")
public Step step1Manager(Step slaveStep) {
return stepBuilderFactory.get("step1.manager")
.<String, String>partitioner("step1", demoPartitioner())
.step(slaveStep)
.gridSize(numerohilos())
.taskExecutor(taskExecutor())
.build();
}
#Bean(name = "demoPartitioner", destroyMethod = "")
public Partitioner demoPartitioner() {
RangePartitioner partitioner = new RangePartitioner();
return partitioner;
}
// slave step
#Bean
public Step slaveStep(ItemReader<beangenerico> demoReader,ItemWriter BeanAccCollectionWriter)
{
return stepBuilderFactory.get("slaveStep")
.chunk(1)
.reader(demoReader)
.processor(compositeProcessor())
.writer(BeanAccCollectionWriter)
.taskExecutor(taskExecutor())
.build();
}
#Bean
public CompositeItemProcessor compositeProcessor() {
List<ItemProcessor> delegates = new ArrayList<>(2);
delegates.add(CustomerProccesor());
delegates.add(beanDataItemProccesor());
CompositeItemProcessor processor = new CompositeItemProcessor();
processor.setDelegates(delegates);
return processor;
}
/***FIXME debemos instanciar los processor como spring bean sino el spring no lee y no toma en cuenta la capa dao o service***/
#Bean
public CustomerItemProcessor CustomerProccesor(){
return new CustomerItemProcessor();
}
#Bean
public beanDataItemProccesor beanDataItemProccesor(){
return new beanDataItemProccesor();
}
/***FIXME debemos instanciar los processor como bean sino no toma en cuenta la capa dao o service***/
#Bean
public CustomItemProcessListener listener() {
return new CustomItemProcessListener();
}
#Bean(name = "demoWriter")
#StepScope
public ItemWriter< beangenerico> CustomItemWriter() {
// TODO Auto-generated method stub
CustomItemWriter wri = new CustomItemWriter();
return wri;
}
#Bean(name = "testWriter")
#StepScope
public ItemWriter<ThreadLocal<CopyOnWriteArrayList<beangen>>> testItemWriter() {
// TODO Auto-generated method stub
TestWriter wri = new TestWriter();
return wri;
}
#Bean(name = "BeanAccCollectionWriter")
#StepScope
public ItemWriter<ThreadLocal<List<NewMessage>>> BeanAccItemWriter() {
// TODO Auto-generated method stub
BeanAccItemWriter wri = new BeanAccItemWriter();
return wri;
}
#Bean(name="flatFileItemWriterPartition")
#StepScope
public FlatFileItemWriter<beangen> slaveWriter(
#Value("#{stepExecutionContext[fromId]}") int fromId,#Value("#{stepExecutionContext[toId]}")int toId ) {
FlatFileItemWriter<beangen> reader = new FlatFileItemWriter<beangen>();
reader.setResource(new FileSystemResource(
"csv/users.processed" + fromId + "-" + toId + ".csv"));
//reader.setAppendAllowed(false);
reader.setLineAggregator(new DelimitedLineAggregator<beangen>() {{
setDelimiter(",");
setFieldExtractor(new BeanWrapperFieldExtractor<beangen>() {{
setNames(new String[]{"usernetwork","cuenta","atributo","atributo2"});
}});
}});
return reader;
}
#Bean(name="tempRecordsWriter")
#StepScope
public ListDelegateWriter ListDelegateWriter(#Qualifier("flatFileItemWriterPartition")FlatFileItemWriter<beangen> writer) {
// TODO Auto-generated method stub
ListDelegateWriter wri = new ListDelegateWriter();
wri.setDelegate(writer);
return wri;
}
#Bean(name = "demoReader")
#StepScope
public ItemReader<beangenerico> myreader(#Value("#{stepExecutionContext['fromId']}") int minValue,#Value("#{stepExecutionContext['toId']}") int maxValue){
Myreader fr = new Myreader(minValue,maxValue);
return fr;
}
#Bean
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor("spring_batch");
}
#Bean
public Job job(#Qualifier("demoPartitionStep") Step demoPartitionStep) {
return this.jobBuilderFactory.get("job")
.start(demoPartitionStep)
.build();
}
#Bean
public StepExecuListner steplistener() {
return new StepExecuListner();
}
public static int numerohilos() {
/****ciclo para hilos usando rango y numero de hilos a calcular***
**************N_threads = N_cpu * U_cpu * (1 + W / C) *************************************
***N_cpu = Runtime.getRuntime().availableProcessors()**
*******/
int numcpu = Runtime.getRuntime().availableProcessors();
int numthread = numcpu*1*(1+10);
int gridSize=numthread;
return gridSize;
}
}

I fix my code, this helped .
public class data implements ItemProcessor<beangenerico,ThreadLocal<List<beanAccountCollect>>> {
Logger logger = Logger.getLogger(data.class);
private String SP_SQL = "{call GetDetailAccount(?)}";
private String SELECT = "{call myspbyblocks (?,?)}";
private beanAccountCollect b;
private ThreadLocal<List<beanAccountCollect>> listbeanAccC = new ThreadLocal<List<beanAccountCollect>>();
private ThreadLocal<List<beanCustomer>> listbeanc=new ThreadLocal<List<beanCustomer>>();
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public ThreadLocal<List<beanAccountCollect>> process(beangenerico rangos) {
// TODO Auto-generated method stub
List<beanParameter> lbeanPar=null;
listbeanAccC.set(new ArrayList<beanAccountCollect>());
try {
listbeanc = this.jdbcTemplate.query(SELECT,new Object [] {rangos.getIni(),rangos.getFin()},new CustomerResultSetExtractor());
for(beanCustomer bc : listbeanc.get()) {
b = new beanAccountCollect();
lbeanPar = new ArrayList<beanParameter>();
lbeanPar = this.jdbcTemplate.query(SP_SQL,new Object [] {bc.getCuenta()},new BeanAccountResulSetExtractor(this.jdbcTemplate));
b.setUsernetwork(bc.getUsernetwork());
b.setTipoagente(bc.getTipoagente());
b.setLbpar(lbeanPar);
listbeanAccC.get().add(b);
}
}catch (Exception e) {
logger.error(e);
}
return listbeanAccC;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}

Related

Spring's #Transactional is not working after flushing the entity in db

I have below class where I used #Transactional, I want when any error occurs in any of the method then transaction should be rolled back.
#Service
#Slf4j
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class CspConfigurationDeployer implements CspConfigurationDeployerInterface {
private CSPConfigDBService cspConfigDBService;
#Override
#Synchronized
#Transactional(rollbackFor = Exception.class)
public Boolean deploy(Map<String, InputStream> inputStreams) throws Exception {
Boolean success = true;
ObjectMapper mapper = new ObjectMapper();
CarrierinfoEntity carrierinfo = null;
CarrierversionEntity carrierversionEntity = null;
try {
if (onboardingcarrierdetailsEntity != null && !ObjectUtils.isEmpty(carrierinfo)) {
carrierversionEntity = cspConfigDBService.getCarrierVersion(carrierinfo.getId(),
onboardingcarrierdetailsEntity.getCarrierversion().getMajorversion());
}
if (ObjectUtils.isEmpty(carrierversionEntity)) {
if (!cspConfigDBService.doesRequestFormExist(carrierinfo.getId(), availablecarrierdetailsEntity.getVersion())) {
availablecarrierdetailsEntity.setCarrierinfo(carrierinfo);
cspConfigDBService.updateEntity(availablecarrierdetailsEntity); // Add request form data
}
}
}
if (onboardingcarrierdetailsEntity != null && ObjectUtils.isEmpty(carrierversionEntity)) {
CarrierversionEntity carrierVersion = onboardingcarrierdetailsEntity.getCarrierversion();
List<CspparametersEntity> cspparametersEntities = carrierVersion.getCarrierParameters();
CarrierversionEntity updatedCarrierVersion = updateCarrierVersion(carrierVersion, carrierinfo.getId());
updateCspParameter(updatedCarrierVersion, carrierinfo.getId(), cspparametersEntities);
List<EnvSpecificParametersEntity> envSpecificParametersEntities = onboardingcarrierdetailsEntity.getEnvSpecificParameters();
OnboardingcarrierdetailsEntity updatedOnboradingDetails = updateOnboardingDetails(onboardingcarrierdetailsEntity,
carrierinfo, updatedCarrierVersion);
updateEnvSpecificParams(updatedOnboradingDetails, envSpecificParametersEntities);
}
} catch (Exception ex) {
log.error("CspConfiguration deployment encountered exception: " + ex.getMessage(), ex);
throw ex;
}
#Repository
#Slf4j
#AllArgsConstructor(onConstructor = #__(#Autowired))
#Transactional(rollbackFor = Exception.class)
public class CSPConfigDBServiceImpl implements CSPConfigDBService {
private final SessionFactory cspConfigurationSessionFactory;
private Session getCspConfigurationSessionFactory() {
return cspConfigurationSessionFactory.getCurrentSession();
}
#Override
public void updateEntity(Object entity) {
Session session = getCspConfigurationSessionFactory();
session.merge(entity);
session.flush();
}
}
when I don't use flush with merge operation then rollback is working but I need the id stored in db immediately for further use so I need to flush it.

How can i use #autowire in runnable spring boot

I have few MongoTemplate and Repos and i need to call them using #Autowire in my runnable class that is being executed by exceutor class using multi threading, now the problem is that when i run the application my AutoWire for mongoTempelate and Repos returns null pointer exception.
Executor class:
#Component
public class MessageConsumer implements ConsumerSeekAware {
#Autowired
AlarmDataRepository alarmDataRepository;
int assignableCores = ((Runtime.getRuntime().availableProcessors()));
ExecutorService executor = Executors.newFixedThreadPool(
assignableCores > 1 ? assignableCores : 1
);
int counter = 0;
List<String> uniqueRecords = new ArrayList<String>();
#KafkaListener(topics = "teltonikaTest", groupId = "xyz")
public void processMessages(#Payload List<String> payload, #Header(KafkaHeaders.RECEIVED_PARTITION_ID) List<Integer> partitions, #Header(KafkaHeaders.OFFSET) List<Long> offsets) throws UnsupportedEncodingException, DecodeException {
System.out.println("assignable resources are: " + assignableCores);
log.info("Batch Size is: {}", payload.size());
if(counter==0){
log.info("Teletonica Packets Received!");
}
for (int i = 0; i < payload.size(); i++) {
log.info("processing message='{}' with partition off-set='{}'", payload.get(i), partitions.get(i) + " _" + offsets.get(i));
}
uniqueRecords = payload.stream().distinct().collect(Collectors.toList());
Runnable worker = new TeltonikaWorkerThread(uniqueRecords);
executor.execute(worker);
counter++;
}
}
public class TeltonikaWorkerThread implements Runnable{
List<String> records;
List<CurrentDevice> currentDevices = new ArrayList<>();
#Autowired
CurrentDeviceRepository currentDeviceRepository;
#Autowired
MongoTemplate mongoTemplate;
public TeltonikaWorkerThread(List<String> records) {
this.records = records;
}
public void run() {
try {
processMessage();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (DecodeException e) {
e.printStackTrace();
}
}
public void processMessage() throws UnsupportedEncodingException,DecodeException {
for(Object record : records){
if(record!="0"){
try{
int IMEILength = record.toString().indexOf("FF");
String IMEI = record.toString().substring(0,IMEILength);
}
catch (Exception e){
e.printStackTrace();
}
}
}
}
}
If I understand correctly, your problem is about multiple beans and Spring doesn't know which one should be injected. There are several options here.
For example, you can use #Qualifier annotation based on the bean name or #Primary annotation.
If your problem is something else, please add an example to your question.

Replace OAuth2AccessTokenJackson2Deserializer with my own custom deserializer

This class is deserializing an oauth2 token and I would like to tweak it. I created my own class extending StdDeserializer<OAuth2AccessToken> which at the moment is the same as the original class.
Here is the class:
public class MyCustomDeserializer extends StdDeserializer<OAuth2AccessToken> {
public MyCustomDeserializer() {
super(OAuth2AccessToken.class);
}
#Override
public OAuth2AccessToken deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
String tokenValue = null;
String tokenType = null;
String refreshToken = null;
Long expiresIn = null;
Set<String> scope = null;
Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>();
// TODO What should occur if a parameter exists twice
while (jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
jp.nextToken();
if (OAuth2AccessToken.ACCESS_TOKEN.equals(name)) {
tokenValue = jp.getText();
}
else if (OAuth2AccessToken.TOKEN_TYPE.equals(name)) {
tokenType = jp.getText();
}
else if (OAuth2AccessToken.REFRESH_TOKEN.equals(name)) {
refreshToken = jp.getText();
}
else if (OAuth2AccessToken.EXPIRES_IN.equals(name)) {
try {
expiresIn = jp.getLongValue();
} catch (JsonParseException e) {
expiresIn = Long.valueOf(jp.getText());
}
}
else if (OAuth2AccessToken.SCOPE.equals(name)) {
scope = parseScope(jp);
} else {
additionalInformation.put(name, jp.readValueAs(Object.class));
}
}
// TODO What should occur if a required parameter (tokenValue or tokenType) is missing?
DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(tokenValue);
accessToken.setTokenType(tokenType);
if (expiresIn != null) {
accessToken.setExpiration(new Date(System.currentTimeMillis() + (expiresIn * 1000)));
}
if (refreshToken != null) {
accessToken.setRefreshToken(new DefaultOAuth2RefreshToken(refreshToken));
}
accessToken.setScope(scope);
accessToken.setAdditionalInformation(additionalInformation);
return accessToken;
}
private Set<String> parseScope(JsonParser jp) throws JsonParseException, IOException {
Set<String> scope;
if (jp.getCurrentToken() == JsonToken.START_ARRAY) {
scope = new TreeSet<String>();
while (jp.nextToken() != JsonToken.END_ARRAY) {
scope.add(jp.getValueAsString());
}
} else {
String text = jp.getText();
scope = OAuth2Utils.parseParameterList(text);
}
return scope;
}
}
Here I am registering the bean:
#Bean
public ObjectMapper configObjectMapper() {
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
final SimpleModule module = new SimpleModule("configModule", com.fasterxml.jackson.core.Version.unknownVersion());
module.addDeserializer(OAuth2AccessToken.class, new MyCustomDeserializer());
objectMapper.registerModule(module);
return objectMapper;
}
Testing the above code the flow doesn't reach my class but the original. I am using spring boot 2.1.4

Dynamic Routing key on RabbitListener Annotation

I need to create a queue linked to Direct Exchange for every user who has logged in to the application. The basement routing will be 'user_' + userId.
That is, every time I receive a message through the user management queue that a user is logged on. Instantiate a bean with scope 'prototype' that contains a method annotated with RabbitListener to declare its queue. To this bean, I passed the userId to be able to configure the name of the queue and routingKey. But I can not access this instance variable in the Spel expression due to a circular reference error.
Here I put the bean with which declares the queue:
#Component("usersHandler")
#Scope(value = "prototype")
public class UsersHandler {
private static Logger logger = LoggerFactory.getLogger(UsersHandler.class);
private Long userId;
public UsersHandler(Long userId) {
this.userId = userId;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
#RabbitListener(bindings
= #QueueBinding(
value = #Queue(
value = "#{'queue_'.concat(usersHandler.userId)}",
durable = "false",
autoDelete = "true",
arguments = {
#Argument(
name = "x-message-ttl",
value = "#{rabbitCustomProperties.directExchange.queueArguments['x-message-ttl']}",
type = "java.lang.Integer"
)
,
#Argument(
name = "x-expires",
value = "#{rabbitCustomProperties.directExchange.queueArguments['x-expires']}",
type = "java.lang.Integer"
)
,
#Argument(
name = "x-dead-letter-exchange",
value = "#{rabbitCustomProperties.directExchange.queueArguments['x-dead-letter-exchange']}",
type = "java.lang.String"
)
}
),
exchange = #Exchange(
value = "#{rabbitCustomProperties.directExchange.name}",
type = ExchangeTypes.DIRECT,
durable = "#{rabbitCustomProperties.directExchange.durable}",
autoDelete = "#{rabbitCustomProperties.directExchange.autoDelete}",
arguments = {
#Argument(
name = "alternate-exchange",
value = "#{rabbitCustomProperties.directExchange.arguments['alternate-exchange']}",
type = "java.lang.String"
)
}
),
key = "#{'user_'.concat(usersHandler.userId)}")
)
public void handleMessage(#Payload Notification notification) {
logger.info("Notification Received : " + notification);
}
}
This is the other bean in charge of creating as many UserHandler as users have logged in:
#Component("adminHandler")
public class AdminHandler implements UsersManadgementVisitor {
#Autowired
private ApplicationContext appCtx;
private Map<Long, UsersHandler> handlers = new HashMap<Long, UsersHandler>();
private static Logger logger = LoggerFactory.getLogger(AdminHandler.class);
#RabbitListener(queues="#{rabbitCustomProperties.adminExchange.queues['users'].name}")
public void handleMessage(#Payload UsersManadgementMessage message) {
logger.info("Message -> " + message);
message.getType().accept(this, message.getId());
}
#Override
public void visitUserConnected(Long idUser) {
logger.info("Declare new queue for user: " + idUser );
UsersHandler userHandler = appCtx.getBean(UsersHandler.class, idUser);
handlers.put(idUser, userHandler);
}
#Override
public void visitUserDisconnected(Long idUser) {
logger.info("Remove queue for user: " + idUser );
handlers.remove(idUser);
}
}
My question is this:
How can I make the variable userId available in the evaluation context of the SpEL expressions?
You could use a ThreadLocal and the T operator...
#SpringBootApplication
public class So43717710Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(So43717710Application.class, args);
UserHolder.setUser("someUser");
context.getBean(Listener.class);
UserHolder.clearUser();
context.getBean(RabbitTemplate.class).convertAndSend("foo", "user_someUser", "bar");
Thread.sleep(5000);
context.close();
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Listener listener() {
return new Listener();
}
public static class Listener {
#RabbitListener(bindings = #QueueBinding(value = #Queue("#{'queue_' + T(com.example.UserHolder).getUser()}"),
exchange = #Exchange(value = "foo"),
key = "#{'user_' + T(com.example.UserHolder).getUser()}"))
public void listen(String in) {
System.out.println(in);
}
}
}
public class UserHolder {
private static final ThreadLocal<String> user = new ThreadLocal<String>();
public static void setUser(String userId) {
user.set(userId);
}
public static String getUser() {
return user.get();
}
public static void clearUser() {
user.remove();
}
}
If the ThreadLocal is in a #Bean you can use a bean reference...
#SpringBootApplication
public class So43717710Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(So43717710Application.class, args);
UserHolder.setUser("someUser");
context.getBean(Listener.class);
UserHolder.clearUser();
context.getBean(RabbitTemplate.class).convertAndSend("foo", "user_someUser", "bar");
Thread.sleep(5000);
context.close();
}
#Bean
public UserHolder holder() {
return new UserHolder();
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Listener listener() {
return new Listener();
}
public static class Listener {
#RabbitListener(bindings = #QueueBinding(value = #Queue("#{'queue_' + #holder.user}"),
exchange = #Exchange(value = "foo"),
key = "#{'user_' + #holder.user}"))
public void listen(String in) {
System.out.println(in);
}
}
}

Does it exist a way for autowiring any Spring #Component inside a JPA repository?

The point is i have a Custom JPA Repository which is load using "#EnableJpaRepositories", but inside of this Custom JPA repository i do autowire another Spring Bean annotated with #Component, but it never comes filled, always bringing a null reference...
I read that JPA Repository does join and share the same Spring Application Context and so it cannot see those Beans loaded by the common Application Context... Is it really true? If so, is there any way to glue them and make Custom Repositories to inject my componentes properly???
Down here the relevant code:
public class DefaultCrudRepository<T extends IdentifiableEntity> extends QuerydslJpaRepository<T, BigInteger>
implements CrudRepository<T> {
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
private JpaEntityInformation<T, BigInteger> jpaEntityInformation;
private EntityManager entityManager;
private EntityPath<T> path;
private PathBuilder<T> builder;
private Querydsl querydsl;
#Autowired
private SortComponent sortComponent;
#Autowired
private PageComponent pageComponent;
#Autowired
private FilterComponent filterComponent;
#Autowired
private ExpandComponent expandComponent;
public DefaultCrudRepository(JpaEntityInformation<T, BigInteger> jpaEntityInformation, EntityManager entityManager,
EntityPathResolver resolver) {
super(jpaEntityInformation, entityManager, resolver);
this.jpaEntityInformation = jpaEntityInformation;
this.entityManager = entityManager;
this.path = resolver.createPath(jpaEntityInformation.getJavaType());
this.builder = new PathBuilder<T>(path.getType(), path.getMetadata());
this.querydsl = new Querydsl(entityManager, builder);
this.expandComponent = new DefaultExpandComponent(entityManager);
this.sortComponent = new DefaultSortComponent();
this.filterComponent = new DefaultFilterComponent();
this.pageComponent = new DefaultPageComponent();
init();
}
public DefaultCrudRepository(JpaEntityInformation<T, BigInteger> jpaEntityInformation,
EntityManager entityManager) {
this(jpaEntityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
this.jpaEntityInformation = jpaEntityInformation;
this.entityManager = entityManager;
}
/*
* private Class<?> getDomainClass(Class<?> clazz) { Type type =
* clazz.getGenericSuperclass(); if (type instanceof ParameterizedType) {
* ParameterizedType parameterizedType = (ParameterizedType) type; return
* (Class<?>) parameterizedType.getActualTypeArguments()[0]; } else { return
* getDomainClass(clazz.getSuperclass()); } }
*/
#PostConstruct
private void init() {
this.filterComponent.init(this.jpaEntityInformation.getJavaType());
this.expandComponent.init(this.jpaEntityInformation.getJavaType());
}
#Override
public <S extends T> List<S> save(Iterable<S> entities) {
List<S> savedEntities = super.save(entities);
super.flush();
this.entityManager.refresh(savedEntities);
return savedEntities;
}
#Override
public <S extends T> S save(S entity) {
S savedEntity = super.save(entity);
super.flush();
if (!this.jpaEntityInformation.isNew(entity)) {
this.entityManager.refresh(savedEntity);
}
return savedEntity;
}
protected JPQLQuery<T> createQuery(final Predicate predicate, final EntityGraph<?> entityGraph) {
JPQLQuery<?> query = createQuery(predicate);
if (entityGraph != null) {
((AbstractJPAQuery<?, ?>) query).setHint(EntityGraphType.LOAD.getKey(), entityGraph);
}
return query.select(path);
}
protected Page<T> findAll(final Pageable pageable, final Predicate predicate, final EntityGraph<?> entityGraph) {
final JPQLQuery<?> countQuery = createCountQuery(predicate);
JPQLQuery<T> query = querydsl.applyPagination(pageable, createQuery(predicate, entityGraph));
return PageableExecutionUtils.getPage(query.fetch(), pageable, new LongSupplier() {
#Override
public long getAsLong() {
return countQuery.fetchCount();
}
});
}
#Override
public Page<T> findAll(Integer pageNumber, Integer pageSize, BooleanExpression booleanExpression,
String filterExpression, String sortExpression, String expandExpression)
throws InvalidFilterExpressionException, InvalidSortExpressionException,
InvalidExpandExpressionException {
Sort sort = null;
if (sortExpression != null && !sortExpression.isEmpty()) {
sort = this.sortComponent.getSort(sortExpression);
}
Pageable pageable = this.pageComponent.getPage(pageNumber, pageSize, sort);
BooleanExpression filterBooleanExpression = null;
if (filterExpression != null) {
filterBooleanExpression = this.filterComponent.getBooleanExpression(filterExpression);
}
BooleanExpression mergedBooleanExpression = null;
if (booleanExpression != null && filterBooleanExpression != null) {
mergedBooleanExpression = booleanExpression.and(filterBooleanExpression);
} else if (booleanExpression != null && filterBooleanExpression == null) {
mergedBooleanExpression = booleanExpression;
} else if (booleanExpression == null && filterBooleanExpression != null) {
mergedBooleanExpression = filterBooleanExpression;
}
EntityGraph<?> entityGraph = null;
if (expandExpression != null && !expandExpression.isEmpty()) {
entityGraph = this.expandComponent.getEntityGraph(expandExpression);
}
return this.findAll(pageable, mergedBooleanExpression, entityGraph);
}
protected Predicate getPredicate(final BigInteger identifier, final Predicate predicate) {
Class<?> clazz = this.jpaEntityInformation.getJavaType();
String name = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, clazz.getSimpleName());
Path<?> rootPath = Expressions.path(this.jpaEntityInformation.getJavaType(), name);
Class<?> idType = this.jpaEntityInformation.getIdType();
String idAttributeName = this.jpaEntityInformation.getIdAttribute().getName();
Path<?> leftPath = Expressions.path(idType, rootPath, idAttributeName);
Expression<?> rightExpression = Expressions.constant(identifier);
BooleanExpression booleanExpression = Expressions.predicate(Ops.EQ, leftPath, rightExpression);
BooleanBuilder booleanBuilder = new BooleanBuilder(booleanExpression);
booleanBuilder.and(predicate);
return booleanBuilder.getValue();
}
protected T findOne(final BigInteger identifier, final BooleanExpression booleanExpression,
final EntityGraph<?> entityGraph) {
Assert.notNull(identifier, "The given id must not be null!");
T object = null;
if (booleanExpression != null) {
Predicate mergedPredicate = getPredicate(identifier, booleanExpression);
JPQLQuery<T> query = createQuery(mergedPredicate, entityGraph);
object = query.fetchOne();
} else {
Map<String, Object> hints = new HashMap<String, Object>();
if (entityGraph != null) {
hints.put("javax.persistence.loadgraph", entityGraph);
}
object = this.entityManager.find(this.jpaEntityInformation.getJavaType(), identifier, hints);
}
return object;
}
#Override
public T findOne(final BigInteger identifier, final BooleanExpression booleanExpression,
final String expandExpression) throws InvalidExpandExpressionException {
EntityGraph<?> entityGraph = null;
if (booleanExpression != null) {
entityGraph = this.expandComponent.getEntityGraph(expandExpression);
}
return this.findOne(identifier, booleanExpression, entityGraph);
}
#Override
public Map<Number, T> findAllRevisions(final BigInteger identifier) {
Assert.notNull(identifier, "The given id must not be null!");
AuditReader auditReader = AuditReaderFactory.get(this.entityManager);
List<Number> revisionList = auditReader.getRevisions(this.jpaEntityInformation.getJavaType(), identifier);
if (revisionList == null || revisionList.isEmpty()) {
return null;
}
Set<Number> revisionSet = new LinkedHashSet<Number>(revisionList);
return auditReader.findRevisions(this.jpaEntityInformation.getJavaType(), revisionSet);
}
#Override
public void delete(Iterable<? extends T> entities) {
super.delete(entities);
super.flush();
}
#Override
public void delete(T entity) {
super.delete(entity);
super.flush();
}
}
public class AbstractCrudService<T extends IdentifiableEntity> implements CrudService<T> {
#Autowired(required=false)
private CrudRepository<T> repository;
#Autowired(required=false)
private NotificationComponent<T> notificationComponent;
private NotificationContext<T> geNotificationContext(String action, List<T> payload) {
DefaultNotificationContext<T> defaultNotificationContext = new DefaultNotificationContext<T>();
/*defaultNotificationContext.setAction(action);
defaultNotificationContext.setObject(this.domainClazz.getSimpleName());
defaultNotificationContext.setInstant(Instant.now());
defaultNotificationContext.setResponsibleId(null);
defaultNotificationContext.setPayload(payload);*/
return defaultNotificationContext;
}
private NotificationContext<T> geNotificationContext(String action, Page<T> payload) {
return geNotificationContext(action, payload.getContent());
}
private NotificationContext<T> geNotificationContext(String action, T payload) {
List<T> payloadList = new ArrayList<T>();
payloadList.add(payload);
return geNotificationContext(action, payloadList);
}
#Override
#Transactional(dontRollbackOn = LongTermRunningException.class)
#TypeTaskCriteria(pre = PreSaveTask.class, post = PostSaveTask.class, referenceGenericType = AbstractCrudService.class)
public List<T> save(List<T> objects)
throws ConcurrentModificationException, UnexpectedException {
List<T> savedObjectList = this.repository.save(objects);
if (this.notificationComponent != null) {
this.notificationComponent.notify(geNotificationContext(NotificationContext.SAVE, savedObjectList));
}
return savedObjectList;
}
#Override
#Transactional(dontRollbackOn = LongTermRunningException.class)
#TypeTaskCriteria(pre = PreSaveTask.class, post = PostSaveTask.class, referenceGenericType = AbstractCrudService.class)
public T save(T object) throws ConcurrentModificationException, UnexpectedException {
T savedObject = this.repository.save(object);
if (this.notificationComponent != null) {
this.notificationComponent.notify(geNotificationContext(NotificationContext.SAVE, savedObject));
}
return savedObject;
}
#Override
#TypeTaskCriteria(pre = PreRetrieveTask.class, post = PostRetrieveTask.class, referenceGenericType = AbstractCrudService.class)
public Page<T> retrieve(
#P(PAGE_NUMBER) final Integer pageNumber,
#P(PAGE_SIZE) final Integer pageSize,
#P(FILTER_EXPRESSION) final String filterExpression,
#P(SORT_EXPRESSION) final String sortExpression,
#P(EXPAND_EXPRESSION) final String expandExpression,
#P(PARAMETERS) final Map<String, String> parameters) throws InvalidParameterException, UnexpectedException {
DefaultRetrieveTaskContext context = TaskContextHolder.getContext();
BooleanExpression booleanExpression = context.getBooleanExpression();
Page<T> page = null;
try {
page = new Page<T>(this.repository.findAll(pageNumber, pageSize, booleanExpression, filterExpression, sortExpression, expandExpression));
} catch (InvalidFilterExpressionException | InvalidSortExpressionException
| InvalidExpandExpressionException e) {
throw new UnexpectedException(e);
}
if (this.notificationComponent != null) {
this.notificationComponent.notify(geNotificationContext(NotificationContext.RETRIEVE, page));
}
return page;
}
#Override
#TypeTaskCriteria(pre = PreRetrieveTask.class, post = PostRetrieveTask.class, referenceGenericType = AbstractCrudService.class)
public T retrieve(BigInteger identifyer, String expandExpression) throws NotFoundException, UnexpectedException {
RetrieveTaskContext context = TaskContextHolder.getContext();
BooleanExpression booleanExpression = context.getBooleanExpression();
T object = null;
try {
object = this.repository.findOne(identifyer, booleanExpression, expandExpression);
} catch (InvalidExpandExpressionException invalidExpandExpressionException) {
throw new UnexpectedException(invalidExpandExpressionException);
}
if (this.notificationComponent != null) {
this.notificationComponent.notify(geNotificationContext(NotificationContext.RETRIEVE, object));
}
return object;
}
#Override
#Transactional(dontRollbackOn = LongTermRunningException.class)
#TypeTaskCriteria(pre = PreDeleteTask.class, post = PostDeleteTask.class, referenceGenericType = AbstractCrudService.class)
public void delete(List<T> objects) throws ConcurrentModificationException, UnexpectedException {
this.repository.delete(objects);
if (this.notificationComponent != null) {
this.notificationComponent.notify(geNotificationContext(NotificationContext.DELETE, (List<T>) null));
}
}
#Override
#Transactional(dontRollbackOn = LongTermRunningException.class)
#TypeTaskCriteria(pre = PreDeleteTask.class, post = PostDeleteTask.class, referenceGenericType = AbstractCrudService.class)
public void delete(T object) throws ConcurrentModificationException, UnexpectedException {
this.repository.delete(object);
if (this.notificationComponent != null) {
this.notificationComponent.notify(geNotificationContext(NotificationContext.DELETE, (T) null));
}
}
}
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(value = "br.org.ccee", repositoryFactoryBeanClass = CrudRepositoryFactoryBean.class)
#EnableAspectJAutoProxy
public class ServiceConfiguration {
#Bean
//#Scope("request")
public ServiceContext serviceContext() {
DefaultServiceContext defaultServiceContext = new DefaultServiceContext();
defaultServiceContext.setInstant(Instant.now());
defaultServiceContext.setUserId(new BigInteger("33"));
defaultServiceContext.setTenantId(new BigInteger("69"));
return defaultServiceContext;
}
#Bean
public TenantEventListener tenantEventListener() {
return new TenantEventListener();
}
#Bean
public AuditEventListener auditEventListener() {
return new AuditEventListener();
}
#Bean
public EventListenerRegistry eventListenerRegistry(
LocalContainerEntityManagerFactoryBean entityManagerFactory,
TenantEventListener tenantEventListener,
AuditEventListener auditEventListener) {
SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) entityManagerFactory.getNativeEntityManagerFactory();
ServiceRegistryImplementor serviceRegistryImplementor = sessionFactoryImpl.getServiceRegistry();
EventListenerRegistry eventListenerRegistry = serviceRegistryImplementor.getService(EventListenerRegistry.class);
eventListenerRegistry.prependListeners(EventType.PRE_INSERT, auditEventListener);
eventListenerRegistry.prependListeners(EventType.PRE_INSERT, tenantEventListener);
eventListenerRegistry.prependListeners(EventType.PRE_UPDATE, auditEventListener);
return eventListenerRegistry;
}
}
public class DefaultCrudRepository<T extends IdentifiableEntity> extends QueryDslJpaRepository<T, BigInteger>
implements CrudRepository<T> {
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
private JpaEntityInformation<T, BigInteger> jpaEntityInformation;
private EntityManager entityManager;
private EntityPath<T> path;
private PathBuilder<T> builder;
private Querydsl querydsl;
#Autowired
private SortComponent sortComponent;
#Autowired
private PageComponent pageComponent;
#Autowired
private FilterComponent filterComponent;
#Autowired
private ExpandComponent expandComponent;

Resources