- java 19
- vavr (latest)
I would like to create a processing flow of steps (processing XML file) that can split the flow to sub-processing steps. Each step can fail so I wrap it in an Either (vavr) to control the flow.
- load XML file (from cloud storage)
- parse XML -> List< Obj >
- LIST< Obj > -> List< JSON >
- LIST< JSON > -> LIST< File >
- FILE -> store each one on cloud storage (network)
- Each processing step can fail.
- Splitting the flow from one file to many people
- Using Either looks like the right way to go as I would like to all succeed or fail.
** This is a mockup code
public class Main {
private Cloud cloud;
public static void main(String[] args) {
Main main = new Main();
main.retrieve("path/filename.xml")
.flatMap(file -> main.parse(file))
.flatMap(people -> main.toUsers(people))
// I would like to break the inner Either to a Seq and process each one of the users
// to a file and store it separately
.flatMap(users -> main.store(users))
// if one file store ops fail I would like to stop and retry the operation.
.peekLeft(error -> System.out.println(error.formatted()));
}
/**
* Store each user in cloud storage Can fail per file
*
* @param users
* @return io.vavr.control.Either
*/
private Either<Error, String> store(List<User> users) {
return Try.of(
() -> {
for (User user: users) {
store(user);
}
return "success";
})
.toEither()
.mapLeft(throwable -> new FIleStoreError(throwable.getMessage()));
}
/**
* network file storage use cloud API to store the file
*
* @param user
* @throws RuntimeException
*/
private void store(User user) throws RuntimeException {
cloud.store(user);
}
private Either<Error, List<User>> toUsers(List<Person> people) {
return Try.of(() -> people.map(person -> new User(person.name())).toList())
.toEither()
.mapLeft(throwable -> new ParseError(throwable.getMessage()));
}
/**
* Read a list of Person from a file
*
* @param file
* @return io.vavr.control.Either
*/
private Either<Error, List<Person>> parse(File file) {
return Try.of(() -> poeple(file))
.toEither()
.mapLeft(throwable -> new ParseError(throwable.getMessage()));
}
/**
* Load list from {@link Person} objects from file
*
* <p>Can fail!
*
* @param file input with people data
* @return list of {@link Person}
* @throws Exception may fail with file operations
*/
private List<Person> poeple(File file) throws Exception {
return List.of(new Person("A"), new Person("B"));
}
/**
* load a file from cloud
*
* @param name
* @return io.vavr.control.Either
*/
public Either<Error, File> retrieve(String name) {
return Try.of(() -> loadFile(name))
.toEither()
.mapLeft(throwable -> new FileLoadingError(throwable.getMessage()));
}
/**
* Load file from network
*
* @param name file name to load
* @return the file
* @throws Exception can fail
*/
private File loadFile(String name) throws Exception {
return new File(name);
}
}
How to convert an Either<Error, List< User >>
to a Seq
of Either<Error, User>
so it can be processed one by one?