How can I parse.Float an application properties? - spring-boot

My current code when I use inputstream. prop = new properties;
Application = prop.getProperty("Application");
servers = prop.getProperty("SERVERS");
username = prop.getProperty("USER_NAME");
password = prop.getProperty("PASSWORD");
Float criticalThreshold = Float.parseFloat(prop.getProperty("THRESHOLD_CRITICAL"));
Float badThreshold = Float.parseFloat(prop.getProperty("THRESHOLD_BAD"));
I recently implemented my application properties into my java class using spring boots way.
#Value("${Application}")
private String Application;
#Value("${SERVERS}")
private String servers;
#Value("${USER_NAME}")
private String username;
#Value("${PASSWORD}")
private String password;
But I do not know how to rewrite the Float.parseFloat
Float criticalThreshold = Float.parseFloat(prop.getProperty("THRESHOLD_CRITICAL"));
Float badThreshold = Float.parseFloat(prop.getProperty("THRESHOLD_BAD"));
I tried but it automatically gives me an compiler error.
#Value("${THRESHOLD_CRITICAL}")
private Float criticalThreshold;
#Value("${THRESHOLD_BAD}")
private Float badThreshold;

#Value lets you specify a method to call to alter the injected property:
#Value("#{T(java.lang.Float).parseFloat('${THRESHOLD_CRITICAL}')}")
private float criticalThreshold;
I tested it and it also works without the full package name:
#Value("#{T(Float).parseFloat('${THRESHOLD_CRITICAL}')}")
private float criticalThreshold;

You can refer the solution suggested by Alex as it does not require the additional variable like in the below approach.
You can't directly do that, but you can achieve that #PostConstruct and declaring one more variable criticalThresholdFloatValue like below:
#Value("${THRESHOLD_CRITICAL}")
private String criticalThreshold;
private float criticalThresholdFloatValue;
#PostConstruct
public void init() {
criticalThresholdFloatValue = Float.parseFloat(criticalThreshold);
}
Now, you can start using criticalThresholdFloatValue where ever you are using in the bean methods.

Related

use of #Value Spring annotation during Controller initialization issue

Probably someone else might have asked something similar as well, but I couldn't find an answer that provides a solution that works...
I'm in the process of learning spring boot and while I was playing with guava RateLimiter during my experiments I hit the following problem:
RateLimiter needs to be created during the Controller initialization, but if I want to load the rate I have to hardcode it, since if I try to load it from props using attributes with #Value Spring annotations it doesn't work.
Is there any "trick" around this "limitation"?
see code below:
#RestController
public class LoggingController {
private Logger logger = LoggerFactory.getLogger(LoggingController.class);
#Value("${count}")
private Double PERMITS_COUNT;
#Value("${seconds}")
private Double PERMITS_PER_SECONDS;
#Value("${consumed}")
private int PERMITS_CONSUMED;
//# Value fails here with NullPointerException
private RateLimiter rateLimiter = RateLimiter.create(PERMITS_COUNT / PERMITS_PER_SECONDS);
// This works file
private RateLimiter rateLimiter = RateLimiter.create(10d / 60d);
private AtomicInteger index = new AtomicInteger(0);
#GetMapping("/logging")
#ResponseBody
public String logging (#RequestParam(name="name", required=false, defaultValue="JavaBoss") String name) {
//#Value works fine if used here
rateLimiter.setRate(PERMITS_COUNT / PERMITS_PER_SECONDS);
rateLimiter.acquire(PERMITS_CONSUMED);
...
Many thanks in advance...
Use PostConstruct and you should be fine
#RestController
public class LoggingController {
private Logger logger = LoggerFactory.getLogger(LoggingController.class);
#Value("${count}")
private Double PERMITS_COUNT;
#Value("${seconds}")
private Double PERMITS_PER_SECONDS;
#Value("${consumed}")
private int PERMITS_CONSUMED;
private RateLimiter rateLimiter;
#PostConstruct
private void createRateLimiter() {
rateLimiter = RateLimiter.create(PERMITS_COUNT / PERMITS_PER_SECONDS);
}
private AtomicInteger index = new AtomicInteger(0);
#GetMapping("/logging")
#ResponseBody
public String logging (#RequestParam(name="name", required=false, defaultValue="JavaBoss") String name) {
...

Why Spring KafkaTemplate doesn't set its instance variable "messageConverter" to volatile?

I was reading source code of Spring KafkaTemplate(org.springframework.kafka.core) and came across this piece of code:
protected final Log logger = LogFactory.getLog(this.getClass()); //NOSONAR
private final ProducerFactory<K, V> producerFactory;
private final boolean autoFlush;
private final boolean transactional;
private final ThreadLocal<Producer<K, V>> producers = new ThreadLocal<>();
private RecordMessageConverter messageConverter = new MessagingMessageConverter();
private volatile String defaultTopic;
private volatile ProducerListener<K, V> producerListener = new LoggingProducerListener<K, V>();
As you see, variables like defaultTopic and producerListener are set to volatile which I presume to make them memory visible once being changed.
So I am confused why meesageConverter was not set to the same.
We generally don't expect configuration properties, such as the message converter to be changed at runtime so there is no need to make it volatile. If you have such a requirement, subclass the template and override the setter with a synchronized method (calling super.set...()).
You are looking at an older version of the code; those variables are no longer volatile.

Spring Data MongoDB - how to set maxTimeMS for Aggregation pipeline query

I've noticed that org.springframework.data.mongodb.core.aggregation.AggregationOption class covers just a small subset of these options described within MongoDB Aggregation pipeline documentation: https://docs.mongodb.com/manual/reference/command/aggregate/#syntax
I need to set maxTimeMS option, but it is not available within org.springframework.data.mongodb.core.aggregation.AggregationOption:
public class AggregationOptions {
private static final String BATCH_SIZE = "batchSize";
private static final String CURSOR = "cursor";
private static final String EXPLAIN = "explain";
private static final String ALLOW_DISK_USE = "allowDiskUse";
private static final String COLLATION = "collation";
private static final String COMMENT = "comment";
...
However, the another class (of mongodb-driver) actually has such field maxTimeMS,
com.mongodb.AggregationOptions:
public class AggregationOptions {
private final Integer batchSize;
private final Boolean allowDiskUse;
private final OutputMode outputMode;
private final long maxTimeMS;
private final Boolean bypassDocumentValidation;
private final Collation collation;
...
Any idea/tricks how to set this maxTimeMS for Aggregation query using Spring Data MongoDB API? Or maybe do I need to build/write such aggregation by using native query?
Btw. I know that Spring Data MongoDB supports maxTimeMS for find operations, for example:
Query.query(mongoCriteria).with(pageable).maxTime(Duration.ofMinutes(4))
However I need to set aggregation query processing timeout on server side in order to prevent "never ending" queries that kill performance.
spring-data-mongodb:2.2.0.RELEASE
I was trying to set a time limit to my query and it took me some time to find the answer; so, I want to share my method with anyone who might be interested:
AggregationOptions aggregationOptions = new AggregationOptions.Builder().maxTime(Duration.ofSeconds(3)).build();
Aggregation aggregate = Aggregation.newAggregation(match).withOptions(aggregationOptions);

Add data to database from Controller, different methods but same row

I have an entity model, for simplification purposes let's say it looks like this :
public class Results {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long firstUser;
private Long secondUser;
private Double average;
private Double median;
private Double score;
}
This is my ResultsService Implementation:
public class ResultsServiceImpl implements ResultsService{
#Autowired
private CalculateDataRepository calculateDataRepository;;
#Autowired
private ResultsService resultsService;
Results results=new Results();
public void Average(Long id1, Long id2){
UserData firstClient = calculateDataRepository.findOne(id1);
userData secondClient = calculateDataRepository.findOne(id2);
clientId = firstClient.getClient().getId();
secondId = secondClient.getClient().getId();
Double average=(firstClient.getA()+secondClient.getA())/2;
results.setAverage(average);
}
public void Score(Long id1, Long id2){
SurveyData firstClient = surveyDataRepository.findOne(id1);
SurveyData secondClient = surveyDataRepository.findOne(id2);
clientId = firstClient.getClient().getId();
secondId = secondClient.getClient().getId();
Double average=(firstClient.getB()+secondClient.getB());
results.setScore(average);
results.setFirstUser(clientId );
results.setSecondUser(secondId );
resultsService.save(results);
}
....
I tried declaring Results results=new Results(); inside every method, but when I save them they get saved in different rows, instead of the same one.
How do I hold the reference so that when I call the setter of a field in one function, it's in the same row as the setter of a field in the other function.
To keep the problem focused, I tried to avoid showing the implementation of calculateDataRepository which is just the repository of an entity where some results are saved for different users.
The Results Method has no foreign field reference nor a reference from somewhere else, as there are fields firstUser and secondUser which I set from one of the methods;
Thank you.
Edit:
Results results=resultsService.findByFirstUserAndSecondUser(clientId, secondId);
if(results==null) {
results= new Results();
// Store to db ?
}
results.setAverage();
resultsService.save(results);
Actually you need a method in ResultsRepository
Results findByFirstAndSecond(Long first, Long second);
In the each Average and Score methods (BTW Java naming convention requires to have method names start from lowercase letter) call the findByFirstAndSecond(id1, id2)
If the method returns null (no such result) create a new instance and save in the DB (INSERT). If some Results is returned store the info there and save changes in DB (UPDATE).

preprocess configuration values in Spring

In a Spring bean, I need to process a configuration property before using is, e.g.:
#Component
class UsersController {
#Value("${roles}")
private String rolesAsString;
private List<String> roles;
#PostConstruct
public void initRoles() {
// just an example, not necessarily string splitting
roles = rolesAsString.split(",");
}
This works, but I am left with an unneeded member variable 'rolesString'. What would be a clean concise way to only keep the processed value?
Properties is
roles=role1,role2,role3
Code is :
#Value("#{'${roles}'.split(',')}")
private List<String> roles;

Resources