#Autowired entity is getting null - spring

#Component
public class TempTry implements CommandLineRunner{
#Autowired
TokenRepository tkeRepo;
#Parameter(names = { "--email", "-e" })
String email;
static final Logger logger = LoggerFactory.getLogger(TempTry.class);
#Override
public void run(String... args) throws Exception {
logger.info("ApplicationStartupRunner run method Started !!");
TempTry main = new TempTry();
JCommander.newBuilder().addObject(main).build().parse(args);
main.runtask();
}
public void runtask() {
LocalDateTime expiryTime = LocalDateTime.now().plusDays(1);
String uuid = UUID.randomUUID().toString();
TokenEntity tknEntity = new TokenEntity();
tknEntity.setEmailId(email);
tknEntity.setExpiryTime(DateUtils.asDate(expiryTime));
tknEntity.setStatus(ResetPasswordStatus.ACTIVE);
tknEntity.setToken(uuid);
tkeRepo.save(tknEntity);
String fromString = UUID.nameUUIDFromBytes("SomeString".getBytes()).toString();
System.out.println("For email " + mail + " UUID=" + uuid + " is stored at time " + new Date());
System.out.println("UUID generated from String is " + fromString);
}
}
I set run configuration as -e dhanrajtijare#gmail.com ..getting email value as expected.
My problem here is at line tkeRepo.save(tknEntity); tkeRepo is null

Here
TempTry main = new TempTry();
How do you expect #Autowire to work if you are creating instance yoursefl?
Your current instance seems to be in app context by that point, so
#Override
public void run(String... args) throws Exception {
logger.info("ApplicationStartupRunner run method Started !!");
JCommander.newBuilder().addObject(this).build().parse(args);
runtask();
}
I put aside the fact that IMHO its just bad to mix JCommander with Spring CLI - use either one or another.

Related

java.lang.IllegalArgumentException: Could not find field 'isBoolean' of type [class java.lang.Boolean] on target object

When I run test then it failed at this point ReflectionTestUtils.setField(service, SeRepositoryImpl.class, "isBoolean",true,Boolean.class) complains about Could not find field 'isBoolean' of type not found. Error trace as below.
I am not sure why because my repositoryImpl class has isBoolean variable defined.
java.lang.IllegalArgumentException: Could not find field 'isBoolean' of type [class java.lang.Boolean] on target object [lautomation.repository.impl.SaRepositoryImpl#4a178d1e] or target class [lautomation.repository.impl.SaRepositoryImpl]
at org.springframework.test.util.ReflectionTestUtils.setField(ReflectionTestUtils.java:175)
test class looks like
#MockBean(name = "seRepository")
PolicyRepository seRepository;
#InjectMocks
private SeRepositoryImpl service;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testUpdateStatus() throws Exception{
ReflectionTestUtils.setField(service, SeRepositoryImpl.class, "isBoolean",true,Boolean.class);
List<Policy> policies = Arrays.asList(new Policy[] {new Policy() });
service.updateIssuedStatus(Mockito.any(Policy.class));
Mockito.verify(seRepository, Mockito.times(1)).updateIssuedStatus(Mockito.any(Policy.class));
}
}
Respository implementation class SeRepositoryImpl has isBoolean variable defined
#Repository("seRepository")
#Log4j
public class SeRepositoryImpl implements PolicyRepository {
#Value("${change-db}")
private boolean isBoolean;
#Autowired
#Qualifier("jdbcDbName")
private NamedParameterJdbcTemplate jdbcTemplate;
#Override
public void updateIssuedStatus(final Policy policy) {
if(!isBoolean) {
log.warn("isBoolean is set to false - skipping db write.");
return;
}
final HashMap<String, String> params = new HashMap<>();
params.put("issued",
new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
params.put("id", Integer.toString(policy.getId()));
jdbcTemplate.update(updateIssuedStatus, params);
String currDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
log.info("params:"+Integer.toString(policy.getId())+" Date:"+currDate);
final String sql = "call usp_updateDatabase(:policy,:currDate)";
MapSqlParameterSource value = new MapSqlParameterSource();
value.addValue("id",Integer.toString(policy.getId()));
value.addValue("stop_dt",new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
jdbcTemplate.update(sql, value);
}
}

Why are the application config values parsed by my custom Spring PropertySourceLoader not being used?

I am attempting to write a TOML PropertySourceLoader implementation. I took a look at some other examples on GitHub and stackoverflow, all of which seem to eventually parse the result out to a map and then return an OriginTrackedMapPropertySource, which is what I tried below:
public final class TomlPropertySourceFactory implements PropertySourceFactory {
#Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
if (!ClassUtils.isPresent("com.fasterxml.jackson.dataformat.toml.TomlFactory", null)) {
throw new IllegalStateException(
"Attempted to load " + name + " but jackson-dataformat-toml was not found on the classpath");
}
if (!ClassUtils.isPresent("com.fasterxml.jackson.core.io.ContentReference", null)) {
throw new IllegalStateException(
"Attempted to load " + name + " but jackson-core was either not found on the classpath or below version 2.13.0");
}
final ObjectMapper mapper = new ObjectMapper(new TomlFactory());
final Map<String, Object> resultMap = mapper.convertValue(mapper.readTree(resource.getInputStream()), new TypeReference<Map<String, Object>>(){});
return new OriginTrackedMapPropertySource(Optional.ofNullable(name).orElseGet(resource.getResource()::getFilename), resultMap);
}
}
public final class TomlPropertySourceLoader implements PropertySourceLoader {
#Override
public String[] getFileExtensions() {
return new String[]{"tml", "toml"};
}
#Override
public List<PropertySource<?>> load(final String name, final Resource resource) throws IOException {
final EncodedResource encodedResource = new EncodedResource(resource);
return Collections.singletonList(new TomlPropertySourceFactory().createPropertySource(name, encodedResource));
}
}
This code does seem to more or less do what is expected; it is executed when application.toml is present, it loads and parses the file out to a <String, Object> map, but from there, none of the actual properties seem to be present in the application — be it when using #Value, #ConfigurationProperties or even when attempting to set stuff like the port Tomcat runs on.
There's not a ton of information available on the internet, without digging into the depths of Spring, about what exactly it is expecting. I'm not sure if the problem is due to how my map is structured or perhaps due to something with the name.
Below you can find my application.toml file:
[spring.datasource]
url = "jdbc:hsqldb:file:testdb"
username = "sa"
[spring.thymeleaf]
cache = false
[server]
port = 8085
[myapp]
foo = "Hello"
bar = 42
aUri = "https://example.org/hello"
targetLocale = "en-US"
[myapp.configuration]
endpoints = ["one", "two", "three"]
[myapp.configuration.connectionSettings]
one = "hello"
[myapp.configuration.connectionSettings.two]
two_sub = "world!"
And my configuration classes:
#Data
#NoArgsConstructor
#Component
#ConfigurationProperties("myapp")
public class AppConfig {
private String foo;
private int bar;
private URI aUri;
private Locale targetLocale;
private SubConfiguration configuration;
}
#Data
#NoArgsConstructor
public class SubConfiguration {
private List<String> endpoints;
private Map<String, Object> connectionSettings;
}
As well as my testing controller:
#RestController
#RequiredArgsConstructor
public final class TomlDemoController {
private final AppConfig appConfig;
#GetMapping("/api/config")
AppConfig getConfig() {
return appConfig;
}
}
The issue was the structure of the property map. The keys have to be flattened in order to work. As an example, for a given table:
[server]
port = 8085
Rather than producing a nested map:
Properties = {
"server" = {
"port" = 8085
}
}
Spring is expecting something more like:
Properties = {
"server.port" = 8085
}
A quick solution using the ObjectToMapTransformer found in Spring Integration:
#Override
#SuppressWarnings("unchecked")
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
if (!ClassUtils.isPresent("com.fasterxml.jackson.dataformat.toml.TomlFactory", null)) {
throw new IllegalStateException(
"Attempted to load " + name + " but jackson-dataformat-toml was not found on the classpath");
}
if (!ClassUtils.isPresent("com.fasterxml.jackson.core.io.ContentReference", null)) {
throw new IllegalStateException(
"Attempted to load " + name + " but jackson-core was either not found on the classpath or below version 2.13.0");
}
final ObjectMapper mapper = new ObjectMapper(new TomlFactory());
final Message<JsonNode> message = new GenericMessage<>(mapper.readTree(resource.getInputStream()));
final ObjectToMapTransformer transformer = new ObjectToMapTransformer();
transformer.setShouldFlattenKeys(true);
Map<String,Object> resultMap = (Map<String, Object>) transformer.transform(message).getPayload();
return new OriginTrackedMapPropertySource(Optional.ofNullable(name).orElseGet(resource.getResource()::getFilename), resultMap);
}

Cannot Write Data to ElasticSearch with AbstractReactiveElasticsearchConfiguration

I am trying out to write data to my local Elasticsearch Docker Container (7.4.2), for simplicity I used the AbstractReactiveElasticsearchConfiguration given from Spring also Overriding the entityMapper function. The I constructed my repository extending the ReactiveElasticsearchRepository
Then in the end I used my autowired repository to saveAll() my collection of elements containing the data. However Elasticsearch doesn't write any data. Also i have a REST controller which is starting my whole process returning nothing basicly, DeferredResult>
The REST method coming from my ApiDelegateImpl
#Override
public DeferredResult<ResponseEntity<Void>> openUsageExporterStartPost() {
final DeferredResult<ResponseEntity<Void>> deferredResult = new DeferredResult<>();
ForkJoinPool.commonPool().execute(() -> {
try {
openUsageExporterAdapter.startExport();
deferredResult.setResult(ResponseEntity.accepted().build());
} catch (Exception e) {
deferredResult.setErrorResult(e);
}
}
);
return deferredResult;
}
My Elasticsearch Configuration
#Configuration
public class ElasticSearchConfig extends AbstractReactiveElasticsearchConfiguration {
#Value("${spring.data.elasticsearch.client.reactive.endpoints}")
private String elasticSearchEndpoint;
#Bean
#Override
public EntityMapper entityMapper() {
final ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(), new DefaultConversionService());
entityMapper.setConversions(elasticsearchCustomConversions());
return entityMapper;
}
#Override
public ReactiveElasticsearchClient reactiveElasticsearchClient() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(elasticSearchEndpoint)
.build();
return ReactiveRestClients.create(clientConfiguration);
}
}
My Repository
public interface OpenUsageRepository extends ReactiveElasticsearchRepository<OpenUsage, Long> {
}
My DTO
#Data
#Document(indexName = "open_usages", type = "open_usages")
#TypeAlias("OpenUsage")
public class OpenUsage {
#Field(name = "id")
#Id
private Long id;
......
}
My Adapter Implementation
#Autowired
private final OpenUsageRepository openUsageRepository;
...transform entity into OpenUsage...
public void doSomething(final List<OpenUsage> openUsages){
openUsageRepository.saveAll(openUsages)
}
And finally my IT test
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#Testcontainers
#TestPropertySource(locations = {"classpath:application-it.properties"})
#ContextConfiguration(initializers = OpenUsageExporterApplicationIT.Initializer.class)
class OpenUsageExporterApplicationIT {
#LocalServerPort
private int port;
private final static String STARTCALL = "http://localhost:%s/open-usage-exporter/start/";
#Container
private static ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:6.8.4").withExposedPorts(9200);
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(final ConfigurableApplicationContext configurableApplicationContext) {
final List<String> pairs = new ArrayList<>();
pairs.add("spring.data.elasticsearch.client.reactive.endpoints=" + container.getContainerIpAddress() + ":" + container.getFirstMappedPort());
pairs.add("spring.elasticsearch.rest.uris=http://" + container.getContainerIpAddress() + ":" + container.getFirstMappedPort());
TestPropertyValues.of(pairs).applyTo(configurableApplicationContext);
}
}
#Test
void testExportToES() throws IOException, InterruptedException {
final List<OpenUsageEntity> openUsageEntities = dbPreparator.insertTestData();
assertTrue(openUsageEntities.size() > 0);
final String result = executeRestCall(STARTCALL);
// Awaitility here tells me nothing is in ElasticSearch :(
}
private String executeRestCall(final String urlTemplate) throws IOException {
final String url = String.format(urlTemplate, port);
final HttpUriRequest request = new HttpPost(url);
final HttpResponse response = HttpClientBuilder.create().build().execute(request);
// Get the result.
return EntityUtils.toString(response.getEntity());
}
}
public void doSomething(final List<OpenUsage> openUsages){
openUsageRepository.saveAll(openUsages)
}
This lacks a semicolon at the end, so it should not compile.
But I assume this is just a typo, and there is a semicolon in reality.
Anyway, saveAll() returns a Flux. This Flux is just a recipe for saving your data, and it is not 'executed' until subscribe() is called by someone (or something like blockLast()). You just throw that Flux away, so the saving never gets executed.
How to fix this? One option is to add .blockLast() call:
openUsageRepository.saveAll(openUsages).blockLast();
But this will save the data in a blocking way effectively defeating the reactivity.
Another option is, if the code you are calling saveAll() from supports reactivity is just to return the Flux returned by saveAll(), but, as your doSomething() has void return type, this is doubtful.
It is not seen how your startExport() connects to doSomething() anyway. But it looks like your 'calling code' does not use any notion of reactivity, so a real solution would be to either rewrite the calling code to use reactivity (obtain a Publisher and subscribe() on it, then wait till the data arrives), or revert to using blocking API (ElasticsearchRepository instead of ReactiveElasticsearchRepository).

Spring Boot class cast exception in PostConstruct method

I am running a Spring Boot application with a PostConstruct method to populate a POJO before application initialization. This is to ensure that the database isn't hit by multiple requests to get the POJO content after it starts running.
I'm able to pull the data from Oracle database through Hibernate query and store it in my POJO. The problem arises when I try to access the stored data. The dataset contains a list of objects that contain strings and numbers. Just trying to print the description of the object at the top of the list raises a class cast exception. How should I mitigate this issue?
#Autowired
private TaskDescrBean taskBean;
#PostConstruct
public void loadDescriptions() {
TaskDataLoader taskData = new TaskDataLoader(taskBean.acquireDataSourceParams());
List<TaskDescription> taskList = tdf.getTaskDescription();
taskBean.setTaskDescriptionList(taskList);
System.out.println("Task description size: " + taskBean.getTaskDescriptionList().get(0).getTaskDescription());
}
My POJO class:
#Component
public class TaskDescrBean implements ApplicationContextAware {
#Resource
private Environment environment;
protected List<TaskDescription> taskDescriptionList;
public Properties acquireDataSourceParams() {
Properties dataSource = new Properties();
dataSource.setProperty("hibernate.connection.driver_class", environment.getProperty("spring.datasource.driver-class-name"));
dataSource.setProperty("hibernate.connection.url", environment.getProperty("spring.datasource.url"));
dataSource.setProperty("hibernate.connection.username", environment.getProperty("spring.datasource.username"));
dataSource.setProperty("hibernate.connection.password", environment.getProperty("spring.datasource.password"));
return dataSource;
}
public List<TaskDescription> getTaskDescriptionList() {
return taskDescriptionList;
}
public void setTaskDescriptionList(List<TaskDescription> taskDescriptionList) {
this.taskDescriptionList = taskDescriptionList;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
My DAO class:
public class TaskDataLoader {
private Session session;
private SessionFactory sessionFactory;
public TaskDataLoader(Properties connectionProperties) {
Configuration config = new Configuration().setProperties(connectionProperties);
config.addAnnotatedClass(TaskDescription.class);
sessionFactory = config.buildSessionFactory();
}
#SuppressWarnings("unchecked")
public List<TaskDescription> getTaskDescription() {
List<TaskDescription> taskList = null;
session = sessionFactory.openSession();
try {
String description = "from TaskDescription des";
Query taskDescriptionQuery = session.createQuery(description);
taskList = taskDescriptionQuery.list();
System.out.println("Task description fetched. " + taskList.getClass());
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
return taskList;
}
TaskDescription Entity:
#Entity
#Table(name="TASK_DESCRIPTION")
#JsonIgnoreProperties
public class TaskDescription implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="TASK_DESCRIPTION_ID")
private Long taskDescriptionId;
#Column(name="TASK_DESCRIPTION")
private String taskDescription;
public Long getTaskDescriptionId() {
return taskDescriptionId;
}
public void setTaskDescriptionId(Long taskDescriptionId) {
this.taskDescriptionId = taskDescriptionId;
}
public String getTaskDescription() {
return taskDescription;
}
public void setTaskDescription(String taskDescription) {
this.taskDescription = taskDescription;
}
}
StackTrace
Instead of sending the List in the return statement, I transformed it into a JSON object and sent its String representation which I mapped back to the Object after transforming it using mapper.readValue()

spring testing #async method

I'm trying to test if #Async annotation of Spring is working as expected on my project. But It doesn't.
I have this test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = GlobalConfiguration.class)
public class ActivityMessageListenerTest {
#Autowired
private ActivityMessageListener activityMessageListener;
private Long USER_ID = 1l;
private Long COMPANY_ID = 2l;
private Date DATE = new Date(10000000);
private String CLASSNAME = "className";
private Long CLASSPK = 14l;
private Integer TYPE = 22;
private String EXTRA_DATA = "extra";
private Long RECIVED_USER_ID = 99l;
#Before
public void setup() throws Exception {
}
#Test
public void testDoReceiveWithException() throws Exception {
System.out.println("Current thread " + Thread.currentThread().getName());
Map<String, Object> values = new HashMap();
values.put(ActivityMessageListener.PARAM_USER_ID, USER_ID);
values.put(ActivityMessageListener.PARAM_COMPANY_ID, COMPANY_ID);
values.put(ActivityMessageListener.PARAM_CREATE_DATE, DATE);
values.put(ActivityMessageListener.PARAM_CLASS_NAME, CLASSNAME);
values.put(ActivityMessageListener.PARAM_CLASS_PK, CLASSPK);
values.put(ActivityMessageListener.PARAM_TYPE, TYPE);
values.put(ActivityMessageListener.PARAM_EXTRA_DATA, EXTRA_DATA );
values.put(ActivityMessageListener.PARAM_RECEIVED_USER_ID, RECIVED_USER_ID);
Message message = new Message();
message.setValues(values);
MessageBusUtil.sendMessage(MKTDestinationNames.ACTIVITY_REGISTRY, message);
}
}
As you can see I'm printing the name of the current thread.
The class containing the #Async method is:
public class ActivityMessageListener extends BaseMessageListener {
public static final String PARAM_USER_ID = "userId";
public static final String PARAM_COMPANY_ID = "companyId";
public static final String PARAM_CREATE_DATE = "createDate";
public static final String PARAM_CLASS_NAME = "className";
public static final String PARAM_CLASS_PK = "classPK";
public static final String PARAM_TYPE = "type";
public static final String PARAM_EXTRA_DATA = "extraData";
public static final String PARAM_RECEIVED_USER_ID = "receiverUserId";
public ActivityMessageListener() {
MessageBusUtil.addQueue(MKTDestinationNames.ACTIVITY_REGISTRY, this);
}
#Override
#Async(value = "activityExecutor")
public void doReceive(Message message) throws Exception {
System.out.println("Current " + Thread.currentThread().getName());
if (1> 0)
throw new RuntimeException("lalal");
Map<String, Object> parameters = message.getValues();
Long userId = (Long)parameters.get(ActivityMessageListener.PARAM_USER_ID);
Long companyId = (Long)parameters.get(ActivityMessageListener.PARAM_COMPANY_ID);
Date createDate = (Date)parameters.get(ActivityMessageListener.PARAM_CREATE_DATE);
String className = (String)parameters.get(ActivityMessageListener.PARAM_CLASS_NAME);
Long classPK = (Long)parameters.get(ActivityMessageListener.PARAM_CLASS_PK);
Integer type = (Integer)parameters.get(ActivityMessageListener.PARAM_TYPE);
String extraData = (String)parameters.get(ActivityMessageListener.PARAM_EXTRA_DATA);
Long receiverUserId = (Long)parameters.get(ActivityMessageListener.PARAM_RECEIVED_USER_ID);
ActivityLocalServiceUtil.addActivity(userId, companyId, createDate, className, classPK, type, extraData, receiverUserId);
}
}
Here I'm printing the name of the current thread inside of the #Async method, and the name is the same as before, main. So it's not working.
The GlobalConfiguration is:
#Configuration
#EnableAspectJAutoProxy
#EnableTransactionManagement
#ComponentScan({
"com.shn.configurations",
...some packages...
})
public class GlobalConfiguration {...}
And inside one of the specified packages has the activityExecutor bean:
#Configuration
#EnableAsync(proxyTargetClass = true)
public class ExecutorConfiguration {
#Bean
public ActivityMessageListener activityMessageListener() {
return new ActivityMessageListener();
}
#Bean
public TaskExecutor activityExecutor()
{
ThreadPoolTaskExecutor threadPoolTaskExecutor =
new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(10);
threadPoolTaskExecutor.setQueueCapacity(100);
return threadPoolTaskExecutor;
}
}
What I'm doing wrong?
Tricky.
Asynchronous behavior is added through proxying.
Spring provides you with a proxy that wraps the actual object and performs the actual invocation in a separate thread.
It looks something like this (except most of this is done dynamically with CGLIB or JDK proxies and Spring handlers)
class ProxyListener extends ActivityMessageListener {
private ActivityMessageListener real;
public ProxyListener(ActivityMessageListener real) {
this.real = real;
}
TaskExecutor executor; // injected
#Override
public void doReceive(Message message) throws Exception {
executor.submit(() -> real.doReceive(message)); // in another thread
}
}
ActivityMessageListener real = new ActivityMessageListener();
ProxyListener proxy = new ProxyListener(real);
Now, in a Spring world, you'd have a reference to the proxy object, not to the ActivityMessageListener. That is
ActivityMessageListener proxy = applicationContext.getBean(ActivityMessageListener.class);
would return a reference to the ProxyListener. Then, through polymorphism, invoking doReceive would go to the overriden Proxy#doReceive method which would invoke ActivityMessageListener#doReceive through delegation and you'd get your asynchronous behavior.
However, you're in a half Spring world.
Here
public ActivityMessageListener() {
MessageBusUtil.addQueue(MKTDestinationNames.ACTIVITY_REGISTRY, this);
}
the reference this is actually referring to the real ActivityMessageListener, not to the proxy. So when, presumably, you send your message on the bus here
MessageBusUtil.sendMessage(MKTDestinationNames.ACTIVITY_REGISTRY, message);
you're sending it to the real object, which doesn't have the proxy asynchronous behavior.
The full Spring solution would be to have the MessabeBus (and/or its queue) be Spring beans in which you can inject the fully process (proxied, autowired, initialized) beans.
In reality, since CGLIB proxies are really just subclasses of your types, so the ProxyListener above would actually also add itself to the bus since the super constructor would be invoked. It would seem though that only one MessageListener can register itself with a key, like MKTDestinationNames.ACTIVITY_REGISTRY. If this isn't the case, you'd have to show more of that code for explanation.
In your test, if you do
activityMessageListener.doReceive(message);
you should see that asynchronous behavior since activityMessageListener should hold a reference to the proxy.

Resources