RxJava how to handle Error without Quit flow - error-handling

My scenario is like this:
During a flow ,if there is an error happened during an element processing (in this example element is "three"), I still want keep processing the others.
In this example: I want to print "1,2,4,5" however, it just print "1 ,2".
Observable<String> numbers = Observable.just("1", "2", "three", "4", "5");
numbers.map(v->{
return Integer.parseInt(v);
}).onErrorResumeNext(error->{return Observable.just(-1);})
.filter(v-> {
System.out.println("filter value smaller than 0");
return v>0;
})
.subscribe(s -> {
System.out.println(s);
});
}
I checked doc, "onErrorResumeNext" will instead relinquish control to the Observable returned from resumeFunction.
Is there way to print "1,2,4,5"?

The flow stops because there is a crash in map. The only way to avoid the flow being stopped is to not let map crash in your example. Put the parseInt into a try-catch and return -1 from the catch part.
Observable<String> numbers = Observable.just("1", "2", "three", "4", "5");
numbers.map(v -> {
try {
return Integer.parseInt(v);
} catch (NumberFormatException ex) { // <--------------------------------------
return -1;
}
})
.filter(v -> {
System.out.println("filter value smaller than 0");
return v > 0;
})
.subscribe(s -> {
System.out.println(s);
});

Related

Why can't my validator of element-ui-form be called?

Here are codes:
**validateCode:[{validator:(rule, value, callback)=>{
if (!value) {
callback(new Error('you have to input code'))
} else if(this.radioValue=="mobile"){
validatingCo(this.user.mobile,value).then((res)=>{
if(!res.code==20000){
return callback(new Error('the code is wrong or expired'))
} else{
callback()
}
})
}
else{
validatingCo(this.user.email,value).then((res)=>{
if(!res.code==20000){
return callback(new Error('the code is wrong or expired'))
} else{
callback()
}
})
}
}, trigger:'blur'}]
Unfortunately, it didn't execute and no error.
I want to know how to handle it.
I think the problem might be caused by this line:
if(!res.code==20000){
// Some stuff here
}
It should probably read:
if(res.code!=20000){
// Some stuff here
}
!res.code will always evaluate to either true or false. So !res.code==20000 will always be false. No matter the input the following error callback will never execute:
return callback(new Error('the code is wrong or expired'))
Here's a little demo to show that "bar" will always be printed out
function simple_if(number) {
if (!number == 20000) {
return "foo"
} else {
return "bar"
}
}
console.log(`res=20000. Expect 'bar': ${simple_if(2000)}`)
console.log(`res=3. Expect 'foo': ${simple_if(3)}`)
console.log(`res=0. Expect 'foo': ${simple_if(0)}`)

Wait for async forEach

I need to stop my function myFunction() to process, if a zero value gets found in a jsonArray called this.constraint.costs.
this is my 1st function :
myFunction(){
if(this.zeroValueCosts()){
console.log(" Found an integer 0 value, I need to stop my function")
return;
};
}
this is my second supposed async function :
async zeroValueCosts(){
await this.constraint.costs.forEach(function(cost){
if(cost.value = 0){
return true;
}
else{
return false;
}
});
}
It doesn't work, no error displayed
What is the right way to use async/await with a forEach loop result ?
This is the this.constraints.costs array :
costs: [{
"name": "new cost",
"value": 0.06666
},{
"name": "new cost 2",
"value": 0.05666
}]
Well, you dont even need async await
async myFunction(){
if(this.zeroValueCosts()){
return;
};
}
zeroValueCosts(){
return constraint.costs.some(({ value }) => value === 0);
}

How to use Serde to parse a field that might fail to be deserialized without failing the entire deserialization?

I am deserializing some JSON objects which come in as requests. The input body is nested, but a certain field is sometimes misformatted for a variety of reasons. In that situation I still want the rest of the object. This doesn't all have to be done through serde; but what is happening now, is that if a single subfield is messed up, the whole request is trashed. I want to somehow still deserialize that result and just mark the field as errored out. How can this be done?
E.g. the data schema might look like:
struct BigNested {
a: Vec<A>,
b: B, // definition omitted
}
struct A {
keep_this: Foo,
trouble: SometimesBad,
}
trouble is the field that's frequently coming in messed up. I would be happy to (e.g.) turn trouble into a Result<SometimesBad, Whatever> and process it from there, but I don't know how to get serde to let me do that.
certain field is sometimes misformatted
You didn't say how malformed the incoming JSON was. Assuming it's still valid JSON, you can pull this off with Serde's struct flatten and customized deserialization:
The customized deserialization is done in a way that never fails for valid JSON input, although it may not return value of expected type if the input has unexpected format.
But these unexpected fields still need to go somewhere. Serde's struct flatten comes in handy here to catch them since any JSON snippet can be deserialized to a HashMap<String, Value>.
//# serde = { version = "1.0.103", features = ["derive"] }
//# serde_json = "1.0.44"
use serde::{Deserialize, Deserializer, de::DeserializeOwned};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Deserialize, Debug)]
struct A {
keep_this: Foo,
trouble: SometimesBad,
}
#[derive(Deserialize, Debug)]
struct Foo {
foo: i32,
}
#[derive(Deserialize, Debug)]
struct SometimesBad {
inner: TryParse<Bar>,
#[serde(flatten)]
blackhole: HashMap<String, Value>,
}
#[derive(Deserialize, Debug)]
struct Bar {
bar: String,
}
#[derive(Debug)]
enum TryParse<T> {
Parsed(T),
Unparsed(Value),
NotPresent
}
impl<'de, T: DeserializeOwned> Deserialize<'de> for TryParse<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
match Option::<Value>::deserialize(deserializer)? {
None => Ok(TryParse::NotPresent),
Some(value) => match T::deserialize(&value) {
Ok(t) => Ok(TryParse::Parsed(t)),
Err(_) => Ok(TryParse::Unparsed(value)),
},
}
}
}
fn main() {
let valid = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": "one"}}}"#;
println!("{:#?}", serde_json::from_str::<A>(valid));
let extra_field = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": "one"}, "extra": 2019}}"#;
println!("{:#?}", serde_json::from_str::<A>(extra_field));
let wrong_type = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": 1}}}"#;
println!("{:#?}", serde_json::from_str::<A>(wrong_type));
let missing_field = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "baz": "one"}}}"#;
println!("{:#?}", serde_json::from_str::<A>(missing_field));
let missing_inner = r#"{ "keep_this": { "foo": 1 }, "trouble": { "whatever": { "bar": "one"}}}"#;
println!("{:#?}", serde_json::from_str::<A>(missing_inner));
}
(The credit isn't all mine. Serde's issue 1583 basically has everything.)

confusion with onExceptionResumeNext passing a observable as a lambda expression

io.reactivex.rxjava2:rxjava:2.1.13
kotlin_version = '1.2.30'
I have the following Observable and I am trying to throw an exception to test the capture of the exception in OnError. However, when I pass in the following to the onExceptionResumeNext(Observable.just(10)) I get the following output:
1
2
10
onComplete
fun main(args: Array<String>) {
Observable.fromArray(1, 2, 0, 4, 5, 6)
.doOnNext {
if (it == 0) {
throw RuntimeException("Exception on 0")
}
}
.onExceptionResumeNext(Observable.just(10))
.subscribe(
{
println(it)
},
{
println("onError ${it.message}")
},
{
println("onComplete")
} )
}
However, If I pass a lambda expression to that method I get the following output:
1
2
Observable.fromArray(1, 2, 0, 4, 5, 6)
.doOnNext {
if (it == 0) {
throw RuntimeException("Exception on 0")
}
}
.onExceptionResumeNext { Observable.just(10) }
.subscribe(
{
println(it)
},
{
println("onError ${it.message}")
},
{
println("onComplete")
} )
}
Just wondering what is the difference between doing this onExceptionResumeNext(Observable.just(10)) and doing this onExceptionResumeNext { Observable.just(10) }
Many thanks in advance
in the first case you passing observable to onExceptionResumeNext
in case of error in original observable, you'll be resubscribed to observable that is passed to onExceptionResumeNext
that's why you're getting "1" and "2" from original source and then "10" and "onComplete" from Observable.just(10)
in second case, you're using lambda syntax, so you're effectively doing this:
.onExceptionResumeNext(object : ObservableSource {
void subscribe(#NonNull Observer<? super T> observer) {
Observable.just(10)
}
})
as you can see, observer that is passed to you is not getting subscribed. Thus, nothing is emmited after "1" and "2" from initial source
what you should be doing is
.onExceptionResumeNext { observer ->
Observable.just(10).subscribe(observer)
}

RxJava Flowable.Interval backpressure when flatmap with single

I'm having a scenario where I need to periodically call an API to check for a result. I'm using Flowable.interval to create an interval function which calls the API.
However, I'm having trouble with backpressure. In my example below, a new single is created on each tick in the interval. The desired effect is to only call the API if a call is not already in progress
Flowable.interval(1, 1, TimeUnit.SECONDS).flatMap {
System.out.println("Delay $it")
//simulates API call
Single.just(1L).doAfterSuccess {
System.out.println("NEW SINGLE!!!")
}.delay(4, TimeUnit.SECONDS).doAfterSuccess {
System.out.println("SINGLE SUCCESS!!!")
}.toFlowable()
}.subscribeOn(Schedulers.io()).observeOn(Schedulers.computation()).blockingFirst()
I can solve this using a filter variable like so:
var filter = true
Flowable.interval(1, 1, TimeUnit.SECONDS).filter {
filter
}.flatMap {
System.out.println("Delay $it")
Single.just(1L).doOnSubscribe {
filter = true
}.doAfterSuccess {
System.out.println("NEW SINGLE!!!")
}.delay(4, TimeUnit.SECONDS).doAfterSuccess {
System.out.println("SINGLE!!!")
filter = true
}.toFlowable()
}.subscribeOn(Schedulers.io()).observeOn(Schedulers.computation()).blockingFirst()
But it seems like a hacky solution. I've tired applying onBackPressureDrop after the interval function, but it has no effect.
Any suggestions?
You have to constrain flatMap as well:
Flowable.interval(1, 1, TimeUnit.SECONDS)
.onBackpressureDrop()
.flatMapSingle({
System.out.println("Delay $it")
//simulates API call
Single.just(1L).doAfterSuccess {
System.out.println("NEW SINGLE!!!")
}.delay(4, TimeUnit.SECONDS).doAfterSuccess {
System.out.println("SINGLE SUCCESS!!!")
}
}, false, 1) // <----------------------------------------------------------
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.subscribe()