I'm just wondering why using == to check equality of HttpStatus.BAD_REQUEST is not working:
HttpStatus httpStatusCode ...;
if (httpStatusCode == HttpStatus.BAD_REQUEST) {}
I got it working by using equals method:
if (httpStatusCode.equals(HttpStatus.BAD_REQUEST)) {}
But, HttpStatus.OK is working as in:
if (httpStatusCode == HttpStatus.OK) {}
I discovered it when I had this code:
if (httpStatusCode == HttpStatus.OK) {
...
} else if (httpStatusCode == HttpStatus.BAD_REQUEST ) {
...
} else {
...
}
Assumming httpStatusCode is HttpStatus.BAD_REQUEST, instead of going through else if block, it went to else block. But, when I changed == to .equals(), it worked.
I'm using Spring Web 4.3.6.RELEASE. Is there any explanation on this? Thank you
Use value() method:
httpStatusCode.value() == HttpStatus.OK.value()
If you will look inside the HttpStatus.java file, you can see it is an enum and it has a value method which return an int value of the HttpStatus, so you can use it to compare your Status codes.
And .equals works as it checks the enums value as == checks reference.
Related
I've set up a route that when I get a name in my post body I will search the DB and return an ID value.
What I want to do is once there is no ID present in the DB return a 204 status code.
But should that be handled in the service or in my controller?
and
How do I return my specific status code?
#ResponseStatus(HttpStatus.OK)
#PostMapping("/ID_values/")
fun getID(
#RequestBody
name: String
): ResponseEntity<String> = ResponseEntity.ok(IDLookupService.lookupIDValue(name))
}
#Service
class EmailLookupService(
private val IDRepo: IDRepo
) : Logging {
fun lookupIDValue(name: String): String {
val IDLookupResult = IDRepo.findById(name)
return if (IDLookupResult.isPresent) {
IDLookupResult.get().ID.toString()
} else {
// return status code 204
}
}
}
First, you should omit the #ResponseStatus(HttpStatus.OK) annotation if you do not wish to always return a status code of 200. Using that annotation, it would suffice to only specify the response body as return value (i.e specify return type String and then return only result in your example), and Spring would automatically wrap that into a response entity with HTTP-status OK.
Second, you need some way to tell the caller of IDLookupService.lookupIDValue (which should probably be called on an instance of IDLookupService and not the class itself) that there was nothing found. This could be done for instance by changing the return type to String? and return null if nothing was found.
Then you can change getID to return
val result = idLookupService.lookupIDValue(name)
return if(result != null) ResponseEntity.ok(result)
else ResponseEntity("not found", HttpStatus.NO_CONTENT)
If you wish to return something different than a String in the case there was nothing found (like an error object with detailed information; in the example here it is simply the text "not found"), you can change the response type of getID to ResponseEntity<*>.
I'm developing a app with Spring Boot 2.0 and Kotlin using the WebFlux framework.
I want to check if a user id exits before save a transaction. I'm stucked in a simple thing like validate if a Mono is empty.
fun createTransaction(serverRequest: ServerRequest) : Mono<ServerResponse> {
val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java))
transaction.flatMap {
val user = userRepository.findById(it.userId)
// If it's empty, return badRequest()
}
return transaction.flatMap { transactionRepository.save(it).then(created(URI.create("/transaction/" + it.id)).build()) }
}
It is possible to do what I want?
The techniques that allow checking whether Flux/Mono is empty
Using operators .switchIfEmpty/.defaultIfEmpty/Mono.repeatWhenEmpty
Using mentioned operators you will be able to react to the case when Stream has been completed without emitting any elements.
First of all, remember that operators such .map, .flatMap, .filter and many others will not be invoked at all if there no onNext has been invoked.
That means that in your case next code
transaction.flatMap {
val user = userRepository.findById(it.userId)
// If it's empty, return badRequest()
}
return transaction.flatMap { transactionRepository.save(it).then(created(URI.create("/transaction/" + it.id)).build()) }
will not be invoked at all, if transaction will be empty.
In case if there is a requirement for handling cases when your flow is empty, you should consider operators like next in the following manner:
transaction
.flatMap(it -> {
val user = userRepository.findById(it.userId)
})
.swithIfEmpty(Flux.defer(() -> Flux.just(badRequest())));
Actual solution
Also, I have noted that you created two sub-flows from the main transaction. Actually, following code will not be executed at all:
transaction.flatMap {
val user = userRepository.findById(it.userId)
// If it's empty, return badRequest()
}
and will be only executed the last one, which is returned from the method. That happens because you ain't subscribed using operator .subscribe(...).
The second point, you can't subscribe to the same request body more the one time (kind of limitation for WebClient's reponse). Thus you are required to share your request body in the next way, so completed example will be:
fun createTransaction(serverRequest: ServerRequest): Mono<ServerResponse> {
val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java)).cache()
transaction
.flatMap { userRepository.findById(it.userId) }
.flatMap { transaction.flatMap { transactionRepository.save(it) } }
.flatMap { ServerResponse.created(URI.create("/transaction/" + it.id)).build() }
.switchIfEmpty(transaction.flatMap { ServerResponse.badRequest().syncBody("missed User for transaction " + it.id) })
}
Or more simple case without sharing transaction flow but using Tuple:
fun createTransaction(serverRequest: ServerRequest): Mono<ServerResponse> {
val emptyUser = !User()
val transaction = serverRequest.body<Mono<Transaction>>(BodyExtractors.toMono(Transaction::class.java))
transaction
.flatMap { t ->
userRepository.findById(t.userId)
.map { Tuples.of(t, it) }
.defaultIfEmpty(Tuples.of(t, emptyUser))
}
.flatMap {
if (it.t2 != emptyUser) {
transactionRepository.save(it.t1)
.flatMap { ServerResponse.created(URI.create("/transaction/" + it.id)).build() }
} else {
ServerResponse.badRequest().syncBody("missed User for transaction " + it.t1.id)
}
}
}
You can check it using the Mono's provided method hasElement() which is analogous to Optional's isPresent(). The method definition is :
Mono<Boolean> hasElement()
for more details checkout : project reactor documentation
In case you have to perform some action based on this value you can further use switchIfEmpty() to provide with alternate publisher.
Let me start by saying I am a newbie on reactive (java) and on this forum.
I think you cannot really check in this code if a mono is empty because a mono represents code that will be executed later on, so in this code body you won't know yet if its is empty. Does that make sense?
I just wrote something similar in Java which seems to work (but not 100% this is the best approach either):
public Mono<ServerResponse> queryStore(ServerRequest request) {
Optional<String> postalCode = request.queryParam("postalCode");
Mono<ServerResponse> badQuery = ServerResponse.badRequest().build();
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
if (!postalCode.isPresent()) { return badQuery; }
Flux<Store> stores = this.repository
.getNearByStores(postalCode.get(), 5);
return ServerResponse.ok().contentType(APPLICATION_JSON)
.body(stores, Store.class)
.switchIfEmpty(notFound);
}
We can use switchIfEmpty method for this
Below example, I'm checking if the user exists with email if not then add it
userRepository.findByEmail(user.getEmail())
.switchIfEmpty(s -> {
user.setStatus("InActive");
String encodedPassword = DigestUtils.sha256Hex(user.getPassword());
user.setPassword(encodedPassword);
userRepository.save(user).subscribe();
s.onComplete();
}).then(Mono.just(user));
Use Mono with Optional:
return findExistingUserMono
.map(Optional::of)
.defaultIfEmpty(Optional.empty())
.flatMap(optionalUser -> {
if(optionalUser.isPresent()) {
return Mono.error('xxxx');
}
return this.userService.create(optionalUser.get());
});
This way it will always emit Optional value so that the stream will never break.
If we are dealing with the current user, it is easy by doing:
ParseAnonymousUtils.isLinked(ParseUser.getCurrentUser());
But what if I just have bunch of usernames? How can I determine which ones are anonymous? I have tried querying the User table like this:
ParseQuery<ParseUser> queryUser = new ParseUser().getQuery();
queryUser.whereEqualTo("User", usernameString);
queryUser.setLimit(1);
queryUser.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> users, ParseException e) {
if (e == null) {
if (users != null) {
for (ParseUser user : users) {
// do a check
}
}
}
}
}
And tried different ways to do the check but nothing seems to work. For example:
ParseAnonymousUtils.isLinked(user)
always returns false. I have also tried accessing the authData as String:
String authData = user.getString("authData");
if (authData == null) Log.i("authData", "null");
else Log.i("authData", authData);
but always get null. I have also tried casting it as JSONObject hoping to see if I can determine if an anonymous field exists in the JSON:
JSONObject authDataJson = (JSONObject) user.get("authData");
but also always get null.
How can I determine if any given username belongs to an anonymous user? Thanks
I am thinking of moving all my Slf4j logging to replace with Spring AOP.
But now I have some questions on how to use Spring AOP in the following scenarios.
I could see that we can use it to print general method trace logs and some arguments as well.
Lets say a situation like this.
public void methodTest(User object) {
Integer number = object.getValue();
List<Param> params = object.getParams();
if((number == null || number < 1000 || number > 10000)) {
LOGGER.error("Invalid Number- " + number);
//May not throw below exception. Just want to log and continue.
//throw new Exception(ErrorCode.INVALID_USER_NUMBER);
} else if (number == 10000) {
if(params != null && params.size() > 0) {
LOGGER.error("No params supported for number "+number);
throw new Exception(ErrorCode.INVALID_SCALE);
}
return;
}
if(number >= 1000 && number < 10000 && (params == null || params.size() == 0)) {
LOGGER.error("Not all params available");
throw new Exception(ErrorCode.INVALID_PARAM);
}
}
How can we adapt Spring AOP in this case? I have different log statements and values to print based on different logic.
Update: Writing our log statements based on ErrorCode what we received in Aspect looks good?
If we have same error code in few of the scenarios, log statements could be different rt. Is it possible to handle that as well?
Lastly, instead of error scenarios if I have debug statements to be used based on different conditions, do we get the control in Aspect?
Create an Aspect class where you define all your pointcuts and advices:
#Aspect
#Component
public class Foo {
#Pointcut("execution(* com.example.ClassName.methodName(..))")
private void exampleMethod() {}
#Before("exampleMethod()")
public void exampleAdvice() {
//your logging implementation
}
}
here you can find more examples:
https://javamondays.com/spring-aop-beginners-guide/
for unit-testing my asp.net MVC web application, I'd like to mock my IGenericRepository (I'm using Moq).
The method that has to be mocked looks like this:
IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
I've already mocked the repository without any problems:
useraccountRepository = new Mock<IGenericRepository<Useraccount>>();
Now I'd like to tell Moq that when the Get method of my interface is called, a list of useraccounts should be returned:
useraccountRepository.Setup(r => r.Get(u => u.Email == useraccount.Email && u.Password == useraccount.Password)).Returns(useraccounts);
I think there is a mistake in my second lambda because this one works:
useraccountRepository.Setup(r => r.Get(null, null, "")).Returns(useraccounts);
But where's my error?
What also works:
useraccountRepository.Setup(r => r.Get(u => u.Email == useraccount.Email
&& u.Password == useraccount.Password, null, "")).Returns(useraccounts);
It looks like the default parameter values don't apply in my mock. Why is that?
If I use
useraccountRepository.Setup(r => r.Get(u => u.Email == useraccount.Email
&& u.Password == useraccount.Password, null, "")).Returns(useraccounts);
anyway, then the method in my controller throws an exception when the Get message is called:
private bool validateUser(Useraccount useraccount)
{
try
{
Useraccount useraccountLogin = UnitOfWork.UseraccountRepository.Get(
u => u.Email == useraccount.Email && u.Password == useraccount.Password).Single<Useraccount>();
return (useraccountLogin != null);
}
catch (Exception exc)
{
return false;
}
}
Where are my mistakes?
Thank you in advance.
Michael
According to this question Moq.Mock<T> - how to setup a method that takes an expression, setting constraints on expression parameters is unsupported by Moq.