Anyone can explain what is the reason for +99 in #Order(Ordered.HIGHEST_PRECEDENCE + 99) I've seen in some spring documentation?
Ordered.HIGHEST_PRECEDENCE means that some interceptor will have the maximum priority in the chain executed by spring, but for spring, the lower the number the higher the priority.
So if you look at Ordered class, you'll see
HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
Therefore adding +99 will in fact DECREASE the priority.
What is the reason for this, so?
For example, in the end of the section:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#websocket-stomp-authentication-token-based
The reason for #Order(Ordered.HIGHEST_PRECEDENCE + 99) is #Order(Ordered.HIGHEST_PRECEDENCE + 100) in AbstractSecurityWebSocketMessageBrokerConfigurer. #Order(Ordered.HIGHEST_PRECEDENCE + 99) is only needed if you want to implement authorization described in the next section of your link (So that the class with +99 do logic which is needed for authorization +100). Authorization will be done by extending AbstractSecurityWebSocketMessageBrokerConfigurer as described.
Related
I've faced a problem with sub-flows in Spring Integration.
According to documentation (1, 2) I can create a do something like this:
#Bean
fun calculateAndSafeFlow(): IntegrationFlow =
integrationFlow("calculateAndSaveChannel") {
handle(prepareDataResolver)
gateway("calculateChannel")
handle(calculationResultPersistor)
}
#Bean
fun calculateFlow(): IntegrationFlow =
integrationFlow("calculateChannel") {
handle(calculationHandler)
}
Basiclly, I need one flow for just a calculation and second for calculation and storing the results.
My problem is on line with gateway() operator. On this line it just stops processing. The calculationFlow does not take a control and nothing happens.
Calculation handler always returns a result.
Maybe I missed something... Please, help.
When you do a gateway(), then it means the reply must comes back from that call. So, apparently your handle(calculationHandler) does not return. Show us what your calculationHandler is doing and fix it the way it can return something which will be treated as a reply and then it will be sent back to the replyChannel header initiated by that gateway().
I have the following code:
#Service
class Resolver {
fun resolveOneFoo(fooId: Id): Foo =
resolveMultipleFoos(setOf(fooId))[fooId]
fun resolveMultipleFoos(fooIds: Set<Id>): Map<Id, Foo> {
// ... expensive code ...
}
}
I would like to cache the results by fooId.
Meaning
resolver.resolveMultipleFoos(setOf(a, b, c)) // calculate for a, b, c and put a, b, c into cache
resolver.resolveMultipleFoos(setOf(b, d)) // should only calculate d and put it into the cache, retrieve b from cache
resolver.resolveMultipleFoos(setOf(a, c)) // should retrieve a and c from cache, no calculation at all
Putting #Cacheable on resolveMultipleFoos() would mean something different.
The problems I am facing
I cannot use #Cacheable on resolveOneFoo() because it's in the same class. The annotation would not work.
Even bigger problem is a performance issue. resolveOneFoo() is just a convenience method when only one fooId is required. For a greater number of fooIds I must use resolveMultipleFoos() in favor of n times resolveOneFoo().
Inside resolveMultipleFoos() I would have to ask the cache for known fooIds and only calculate the unknown ones, adding them into the cache eventually.
I think the problem is solvable by manually wiring the cacheManager and interact with the Cache directly. But then I would have infringed the IoC concept. I rather have an annotation and have the logic some place else.
My question: Is there a better way?
Greetings venerable SO community...
I come to everyone today in need of a reactive solution for a problem I've not yet encountered.
I would still consider myself a reactive neophyte at this point, and although I've been reading over "Hands On Reactive Programming in Spring" I've still got the boss looking over me and tapping his foot if you know what I mean, so I'm again hoping that some benevolent and brilliant soul might point me in the right direction for an implementation I'm presently tasked with.
Here's the situation:
I have to call an external service providing a list of transactions(containing transaction data) for a given date range.
In addition to the date range being passed in the request to the external service, there's also number of transactions per page, we'll call "N", and page number, we'll call "P."
So say for a certain date range there is a total of 23 transactions.
Then:
For N=10 and P=1 they will return 10 transactions, from 1-10
For N=10 and P=2 we’d get transactions 11-20.
For N=10 and P=3 we’d get transactions 21-23.
For N=10 and P=4 or higher no transactions would be returned.
For N=7 and P=3 we’d get transactions 15-21.
For N=30 and P=1 we’d get all 23 transactions and know that we have all of the transactions because the number returned is less than number requested.
(Please note, we have no idea how many transaction records in total will ultimately be returned.)
So what I'm after is some sort of reactive construct that can potentially repeatedly call the remote transaction list service, check if the total number returned is less than the total number requested, and if not, call again while saving up/accumulating all the records in another list, and then once we reach the end, send this other list of all the transactions back in a response to the service that invoked this code.
Does this make sense, or no?
I've been searching SO, and so far I found this article that seems somewhat applicable and promising using the "repeat" functionality, but I'm really not sure if this is the right path or not.
I also found this article which also seems like it might be relevant.
Again, and as always, any and all help/guidance here is immensely appreciated!
Greetings once again SO community.
I was finally able to come up with a solution for this problem thanks to help from a more experienced co-worker.
public Flux<TransactionListData> getTransactionList(String cardId, TransactionLookupCriteria lookupCriteria) {
return cardService.getByCardId(cardId)
.map(Card::getAccountId)
.flatMap(accountService::getAccount)
.flatMap(account -> fetchTransactions(account, lookupCriteria))
.flatMapMany(Flux::fromIterable)
.map(this::negateTransactionAmountIfNecessary)
.map(this::setTransactionApprovalFlag);
}
private Mono<List<TransactionListData>> fetchTransactions(Account account,
TransactionLookupCriteria lookupCriteria) {
final PageNumber pageNumber = new PageNumber();
return Flux.defer(() -> getTransactions(account, lookupCriteria, pageNumber))
.repeatWhen(transactions -> transactions.takeWhile(transactionCount -> transactionCount == TRANSACTIONS_REQUESTED_PER_PAGE))
.collectList();
}
private Flux<TransactionListData> getTransactions(Account account, TransactionLookupCriteria lookupCriteria, PageNumber pageNumber) {
return Mono.just(createGetTransactionListServiceRequestData(account, lookupCriteria, pageNumber.get()))
.flatMap(cartaClient::getTransactionList)
.map(GetTransactionListServiceResponse::getServiceResponseData)
.switchIfEmpty(Mono.defer(() -> Mono.error(new ServiceException("Transaction response data empty"))))
.doOnNext(x -> pageNumber.increment())
.flatMapIterable(GetTransactionListServiceResponseData::getTransactionList);
}
private class PageNumber {
int page = 1;
void increment() {
page++;
}
public int get() {
return page;
}
}
I need to define Duration value (spring.redis.timeout) by application.properties.
I was trying to use one point defined in Spring boot documentation:
Spring Boot has dedicated support for expressing durations. If you expose a java.time.Duration property, the following formats in application properties are available:
A regular long representation (using milliseconds as the default unit unless a #DurationUnit has been specified)
The standard ISO-8601 format used by java.util.Duration
A more readable format where the value and the unit are coupled (e.g. 10s means 10 seconds)
When i use spring.redis.timeout=3s Spring boot application throws this exception:
Cannot convert value of type 'java.lang.String' to required type
'java.time.Duration': no matching editors or conversion strategy found
Which would it be the best way to set a correct value to a Duration property in application.properties withs last Spring boot 2 release?
Any property which is of type duration can be injected via .properties or .yml files.
All you need to do is use a proper formatting.
If you want to inject a duration of 5 seconds it should be defined as PT5S or pt5s or PT5s
case of the letters doesn't matter, so you use any combination which is readable for you
generally everyone uses all capital letters
Other examples
PT1.5S = 1.5 Seconds
PT60S = 60 Seconds
PT3M = 3 Minutes
PT2H = 2 Hours
P3DT5H40M30S = 3Days, 5Hours, 40 Minutes and 30 Seconds
You can also use +ve and -ve signs to denote positive vs negative period of time.
You can negate only one of the entity for example: PT-3H30M = -3 hours, +30 minutes, basically -2.5Hours
Or You can negate the whole entity: -PT3H30M = -3 hours, -30 minutes, basically -3.5Hours
Double negative works here too: -PT-3H+30M = +3 Hours, -30 Minutes, basically +2.5Hours
Note:
Durations can only be represented in HOURS or lower ChronoUnit (NANOS, MICROS, MILLIS, SECONDS, MINUTES, HOURS) since they represent accurate durations
Higher ChronoUnit (DAYS, WEEKS, MONTHS, YEARS, DECADES,CENTURIES, MILLENNIA, ERAS, FOREVER) are not allowed since they don't represent accurate duration. These ChronoUnits have estimated duration due to the possibility of Days varying due to daylight saving, Months have different lengths etc.
Exception - Java does automatic conversion of DAYS into HOURS, But it doesn't do it for any other higher ChronoUnit (MONTHS, YEARS etc.).
If we try to do a "P1D", java automatically converts it into "PT24H". So If we want to do duration of 1 MONTH, we will have to use PT720H or P30D. In case of P30D java's automatic conversion will take place and give us PT720H
Upvote, if it works for you or you like the explanation. Thanks,
It's possible to use #Value notation with Spring Expression Language
#Value("#{T(java.time.Duration).parse('${spring.redis.timeout}')}")
private Duration timeout;
The Duration in the moment (Spring-Boot 2.0.4.RELEASE) it is not possible to use together with #Value notation, but it is possible to use with #ConfigurationProperties
For Redis, you have RedisProperties and you can use the configuration:
spring.redis.timeout=5s
And:
#SpringBootApplication
public class DemoApplication {
#Autowired
RedisProperties redisProperties;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#PostConstruct
void init() {
System.out.println(redisProperties.getTimeout());
}
}
It printed (parse as 5s):
PT5S
https://docs.oracle.com/javase/8/docs/api//java/time/Duration.html#parse-java.lang.CharSequence-
Update for Spring Boot 2.5.5
We can use #Value annotation together with application.properties values.
For example you have the next property in your application.properties file:
your.amazing.duration=100ms
Then you can use it in the #Value annotation:
#Value("${your.amazing.duration}")
final Duration duration;
That is all.
Supported units:
ns for nanoseconds
us for microseconds
ms for milliseconds
s for seconds
m for minutes
h for hours
d for days
Docs: link
If your Spring-Boot version or its dependencies don't put ApplicationConversionService into context (and Spring-Boot doesn't until 2.1), you can expose it explicitly
#Bean
public ConversionService conversionService() {
return ApplicationConversionService.getSharedInstance();
}
It invokes Duration.parse, so you may use PT3S, PT1H30M, etc in properties files.
Spring Boot attempts to coerce the external application properties to the right type when it binds to the #ConfigurationProperties beans.
If you need custom type conversion, you can provide a ConversionService bean (with a bean named conversionService)
See: https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#boot-features-external-config-conversion
Create new ApplicationConversionService bean (it must be named conversionService ). Here you are my code tested with Spring boot 2.0.4:
#Configuration
public class Conversion {
#Bean
public ApplicationConversionService conversionService()
{
final ApplicationConversionService applicationConversionService = new ApplicationConversionService();
return applicationConversionService;
}
Here you are an example project using this approach:
https://github.com/cristianprofile/spring-data-redis-lettuce
I was getting this error, but only during testing; the bean using a #Value-annotated Duration was otherwise working. It turned out that I was missing the #SpringBootTest annotation on the test case class (and the spring-boot-test dependency that provides it) and that was causing only a subset of standard converters to be available for use.
One colleague in my team says that some methods should have both preconditions & postconditions. But the point is about code coverage, those conditions were not being called (not tested) until an invalid implementation implemented (just used in unit test). Lets take below example.
public interface ICalculator
{
int Calculate(int x, int y);
}
public int GetSummary(int x, int y)
{
// preconditions
var result = calculator.Calculate(x, y);
// postconditions
if (result < 0)
{
**throw new Exception("...");**
}
return result;
}
Two options for us:
1/ Remove test implementations + postconditions
2/ Keep both test implementations + postconditions
Can you give some advice please?
Keep pre- and post-conditions.
You'll need at least four tests here: combinations of (pre, post) x (pass, fail). Your failing post-condition test will pass if the expected exception is thrown.
This is easy to do in JUnit with its #Test(expected = Exception.class) annotation.
Be careful with colleagues that make blanket statements like "X must always be true." Dogma in all its forms should be avoided. Understand the reasons for doing things and do them when they make sense.
These conditions should be seen from design view. They ensure the calculator should be working fine, returning result in a range of expected values.
You should see the MS code contracts project to take a document there.