How to combine data from two reactive streams in project reactor? - java

I started using Project Reactor recently and I can't work out how to work with nested streams. I want to update data of outer Mono with some data of inner Mono.
#GetMapping("/search")
public Mono<Github> combineGithubData() {
WebClient client = WebClient.create("https://api.github.com");
Mono<Github> data = client.get().uri(URI.create("https://api.github.com/users/autocorrectoff")).retrieve().bodyToMono(Github.class);
data = data.map(s -> {
client.get().uri(URI.create("https://api.github.com/users/Kukilej")).retrieve().bodyToMono(Github.class).map(m -> {
s.setXXX(m.getName());
return m;
});
return s;
});
return data;
}
The field XXX is always returned as null, although I have set it to a value from inner Mono. I'm pretty sure this would work in RxJs. How do I make this work with Project Reactor?
edit:
the code of the Github class
import lombok.*;
#Getter #Setter
#Builder
#ToString
#NoArgsConstructor
#AllArgsConstructor
public class Github {
private String login;
private int id;
private String node_id;
private String avatar_url;
private String gravatar_id;
private String url;
private String html_url;
private String followers_url;
private String following_url;
private String gists_url;
private String starred_url;
private String subscriptions_url;
private String organizations_url;
private String repos_url;
private String events_url;
private String received_events_url;
private String type;
private boolean site_admin;
private String name;
private String company;
private String blog;
private String location;
private String email;
private String hireable;
private String bio;
private int public_repos;
private int public_gists;
private int followers;
private int following;
private String created_at;
private String updated_at;
private String XXX;
}

Your inner stream is not getting subscribed to. Either us flatMap, or better yet, use zip:
data
.zipWith(client.get().uri(...).retrieve().bodyToMono(Github.class))
.map(tuple2 -> {
//update tuple2.getT1() with m.getName() and return the updated tuple
return tuple2.mapT1(tuple2.getT1().setXXX(tuple2.getT2().getName()));
})
.map(tuple2 -> tuple2.getT1() //updated s);
zipWith() subscribes to the inner stream.

Related

How can I read data and put into model in java?

I need to get some specific data from rest to my model.
Data I get from rest :
[{"id":595,"name":"TransXChange20210805113332","prosystem_file_id":null,"dataset":16,"creator":113,"editor":113,"created":"2021-08-05T09:45:21.444949Z","edited":"2021-08-05T09:45:27.542152Z","update_from_url":false,"description":"Rozkłady jazdy komunikacji miejskiej ważne od 08.08.2021","file":"https://otwartedane.erzeszow.pl/media/resources/transxchange20210805113332.xml","link":null,"extension":"XML","data_type":"[]","file_name":"transxchange20210805113332.xml","chart_info":null,"map_info":null,"score":4,"public":true,"licence":"other-open","connection_dict":null,"selection_string":null,"db_type":"POSTGRESQL","type":"file","dbview_cache_minutes":1,"preview_base64":null,"gpkg_display_info":null,"archive_to_csv":false},{"id":538,"name":"TransXChange20210513082611","prosystem_file_id":null,"dataset":16,"creator":113,"editor":113,"created":"2021-05-13T06:28:50.233464Z","edited":"2021-07-28T08:52:06.695966Z","update_from_url":false,"description":"Rozkłady jazdy komunikacji miejskiej ważne od 15.05.2021","file":"https://otwartedane.erzeszow.pl/media/resources/transxchange20210513082611.xml","link":null,"extension":"XML","data_type":"[]","file_name":"transxchange20210513082611.xml","chart_info":null,"map_info":null,"score":4,"public":true,"licence":"other-open","connection_dict":null,"selection_string":null,"db_type":"POSTGRESQL","type":"file","dbview_cache_minutes":1,"preview_base64":null,"gpkg_display_info":null,"archive_to_csv":false},{"id":544,"name":"TransXChange20210526143716","prosystem_file_id":null,"dataset":16,"creator":113,"editor":113,"created":"2021-05-26T12:40:42.587492Z","edited":"2021-07-28T08:52:04.417450Z","update_from_url":false,"description":"Rozkłady jazdy komunikacji miejskiej ważne od 01.06.2021","file":"https://otwartedane.erzeszow.pl/media/resources/transxchange20210526143716.xml","link":null,"extension":"XML","data_type":"[]","file_name":"transxchange20210526143716.xml","chart_info":null,"map_info":null,"score":4,"public":true,"licence":"other-open","connection_dict":null,"selection_string":null,"db_type":"POSTGRESQL","type":"file","dbview_cache_minutes":1,"preview_base64":null,"gpkg_display_info":null,"archive_to_csv":false}]
i got it in single line
my code in java :
RestTemplateBuilder builder = new RestTemplateBuilder();
String soc = builder.build().getForObject("https://otwartedane.erzeszow.pl/v1/datasets/16/resources/", String.class);
assert soc != null;
System.out.println(soc);
And the problem is I need to put them into model
My model:
public class Resource {
private long id;
private String name;
private long prosystem_file_id;
private int dataset;
private int creator;
private int editor;
private LocalDateTime created;
private LocalDateTime edited;
private boolean update_from_url;
private String description;
private String file;
private String link;
private String extension;
private String data_type;
private String file_name;
private String chart_info;
private String map_info;
private int score;
private boolean isPublic;
private String licence;
private String connection_dict;
private String selection_string;
private String db_type;
private String type;
private int dbview_cache_minutes;
private String preview_base64;
private String gpkg_display_info;
private boolean archive_to_csv;
All getters and setters are generated.
How can I put them into model for example List?
The problem is I get data like [{resource},{resource},{resource}].
As it states from the RestTemplate documentation
you can call to the getForObject method passing as an argument the desired deserialization class.
Something like:
RestTemplateBuilder builder = new RestTemplateBuilder();
Resource soc = builder.build().getForObject("https://otwartedane.erzeszow.pl/v1/datasets/16/resources/", Resource.class);
assert soc != null;
System.out.println(soc);
I have found answer to my question.
I need to assign my call to array of model.
Resource[] soc =builder.build().getForObject( URL , Resource[].class );

How to Convert MongoDB Query to Spring Data Query

I'm trying to convert the following Mongo query for use with Spring data.
db.product.aggregate([
{$unwind: '$barcodes'},
{$project: {
_id: 0,
productId: '$_id',
productTitle: '$title',
productVariation: '$variation',
barcode: '$barcodes'
}}])
This is what I've been trying so far. It returns the aggregation, but with null values:
UnwindOperation unwindOperation = Aggregation.unwind("barcodes");
ProjectionOperation projectStage = Aggregation.project().and("productId").as("_id").and("productTitle")
.as("title")
.and("productVariation").as("variation")
.and("barcodeTitle").as("barcodes.title")
.and("barcodeValue").as("barcodes.value")
.and("barcodeType").as("barcodes.type")
.and("codeStandard").as("barcodes.codeStandard")
.and("quantity").as("barcodes.quantity")
.and("status").as("barcodes.status");
SortOperation sortOperation = Aggregation.sort(Sort.by(Sort.Direction.DESC, "title"));
Aggregation agg = Aggregation.newAggregation(unwindOperation, projectStage, sortOperation);
AggregationResults<BarcodeAggregateList> results = mongoTemplate.aggregate(agg, "product", BarcodeAggregateList.class);
What it is returning:
The class I am mapping to (has getters/setters):
public class BarcodeAggregateList {
private String productId;
private String productTitle;
private String productVariation;
private String barcodeTitle;
private String barcodeValue;
private String barcodeType;
private String codeStandard;
private int quantity;
private String status;
}
Product class that the data is coming from:
public class Product implements Serializable {
private static final long serialVersionUID = -998149317494604215L;
private String id;
private String title;
private String description;
private String SKU;
private double cost;
private double retailPrice;
private String status;
private LocalDate launchDate;
private LocalDate discontinueDate;
private String discontinueReason;
private String salesChannel;
private List<Barcode> barcodes;
private ProductVariation variation;
private List<Supplier> supplier;
private Product parentProduct;
private boolean updateChildren;
private Label label;
private int secondaryStockLevel;
private int primaryStockLevel;
private Date createdDate;
private Date modifiedDate;
private List<Dimension> dimensions;
private boolean isDeleted = false;
}
Barcode class
public class Barcode {
private String type;
private String title;
private String value;
private String status;
private String codeStandard;
private int quantity;
}
I appreciate any help with this or resources to help me better understand how to perform these types of conversions.
For anyone trying to solve similar issues, I've found the following resources somewhat helpful:
https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.query
https://xpadro.com/2016/04/data-aggregation-with-spring-data-mongodb-and-spring-boot.html
https://www.tutorialspoint.com/get-fields-from-multiple-sub-documents-that-match-a-condition-in-mongodb
BarcodeAggregateList class fields are null because there is a minor issue in ProjectionOperation's and() and as() methods. The correct syntax is
Aggregation.project().and(SOURCE_FIELD).as(TARGET_FIELD)
You have written and("productId").as("_id") , which is wrong
You need to write this as and("_id").as("productId") , because source field is _id
complete code:
UnwindOperation unwindOperation = Aggregation.unwind("barcodes");
ProjectionOperation projectStage = Aggregation.project()
.and("_id").as("productId")
.and("title").as("productTitle")
.and("variation").as("productVariation")
.and("barcodes.title").as("barcodeTitle")
.and("barcodes.value").as("barcodeValue")
.and("barcodes.type").as("barcodeType")
.and("barcodes.codeStandard").as("codeStandard")
.and("barcodes.quantity").as("quantity")
.and("barcodes.status").as("status");
SortOperation sortOperation = Aggregation.sort(Sort.by(Sort.Direction.DESC, "productTitle"));
Aggregation agg = Aggregation.newAggregation(unwindOperation, projectStage, sortOperation);
AggregationResults<BarcodeAggregateList> results = mongoTemplate.aggregate(agg, "product", BarcodeAggregateList.class);

How to find differences between two collections

I have following DTOs:
#Data
public class PersonDTO implements Diffable<PersonDTO> {
private String id;
private String firstName;
private String lastName;
private List<AddressDTO> addresses;
#Override
public DiffResult diff(PersonDTO personDTO) {
return new DiffBuilder(this, personDTO, SHORT_PREFIX_STYLE)
.append("id", this.id, personDTO.getId())
.append("firstName", this.firstName, personDTO.getFirstName())
.append("lastName", this.lastName, personDTO.getLastName())
.append("addresses", addresses, personDTO.getAddresses())
.build();
}
}
#Data
public class AddressDTO implements Diffable<AddressDTO> {
private String id;
private String personId;
private String addressType;
private String street;
private String houseNumber;
private String postalCode;
private String city;
private String countryId;
#Override
public DiffResult diff(AddressDTO addressDTO) {
return new DiffBuilder(this, addressDTO, SHORT_PREFIX_STYLE)
.append("id", this.id, addressDTO.getId())
.append("personId", this.personId, addressDTO.getPersonId())
.append("addressType", this.addressType, addressDTO.getAddressType())
.append("street", this.street, addressDTO.getStreet())
.append("houseNumber", this.houseNumber, addressDTO.getHouseNumber())
.append("postalCode", this.postalCode, addressDTO.getPostalCode())
.append("city", this.city, addressDTO.getCity())
.append("countryId", this.countryId, addressDTO.getCountryId())
.build();
}
}
My main goal is to find differences between two similar person objects. Currently I've tried to use Diffable interface from apache commons which is perfectly good for object. Please advise how to deal with collections when size of each collection can be different. For instance few addresses were removed, few was added and few was updated. Please see example below:
Probably there is another library which helps to achieve similar goals, please advice
source can be your first object
target can be your second object
Iterator targetIt = target.iterator();
for (Object obj:source)
if (!obj.equals(targetIt.next())
// Element has changed

how can i combine 3 List of different object into one new object with Java 8

I have 3 objects List and i would like to combine it base on they unique key into one object List.
Since Loan depend on Account and Account depend on Bank
is there simple way without multiple looping for each object in java 8?
I know its better to do it in single query but wonder if there is something existing with Java 8 using List and combine it into one list.
public class Bank {
private String institution; //pk
private String transit; //pk
private String bankName;
}
public class Account {
private String institution; //pk
private String transit; //pk
private String accountNo; //pk
private String nameAccount;
}
public class Loan {
private String institution;//pk
private String transit;//pk
private String accountNo;//pk
private String serviceNo;//pk
}
// fusion object
public class CombineObject {
private String institution;
private String transit;
private String accountNo;
private String serviceNo;
private String nameAccount;
private String bankName;
}
List<Bank> lstBank = myListBank();
List<Account> lstAccount = myListAccount();
List<Loan> lstLoan = myListLoan();

How to refer to an inner class inside a list in Java

after messing around with parsing a JSON response with GSON for a day, I finally figured out how to get my javabeans right in order to extract my data from the response. This is the layout of my nested classes and lists:
public class LocationContainer {
public class paging {
private String previous;
private String next;
}
private List<Datas> data;
public class Datas {
private String message;
private String id;
private String created_time;
public class Tags {
private List<Data> datas;
public class Data {
private String id;
private String name;
}
}
public class Application {
private String id;
private String name;
}
public class From {
private String id;
private String name;
}
public class Place {
private String id;
private String name;
public class Location {
private int longitude;
private int latitude;
}
}
}
}
Now I am trying to get a hold of the name string inside the place class and the created_time string, but since I am quite a noob, I can't seem to figure it out.
I was able to extract the created_time string by using
String time = gson.toJson(item.data.get(1).created_time);
However using
String name = gson.toJson(item.data.get(1).Place.name);
doesnt work.
The item class is an instance of LocationContainer filled with the output from GSON.
Any pointers would be greatly appreciated.
created_time is a member variable of Data, so your first line is fine.
However, Place is not a member variable, it's just a class definition. You probably need to instantiate a member variable inside your Data class, e.g.:
private Place place;

Categories

Resources