I have a GET request in which the user can pass a list of book codes as a parameter. Like this:
#GetMapping("/books")
public ResponseEntity<Page<BooksView>> findAvailableBooks(#RequestParam(value = "codes") String[] codes
I need to take this array of codes and verify which book codes exist in the database and if they are available in stock to return them as a Spring page. I tried this:
1) First check if the code array is filled
2) If so, for each code in the array I check with mongo repository if that code exists in the database and if the available is true
3) If so, I add the current code to a list
4) But I don't know if this logic works (is there a simpler or cleaner way to do it?) and I also don't know how to treat this list so that the return is a Page
public Page<Book> findBooks(String[] codes) {
if(codes.length > 0) {
List<String> listOfCodes = null;
for (String code : codes){
if(repository.existsByCodeAndAvailable(Long.parseLong(code))){
listOfCodes.add(code);
}
}
return ???
}
}
you can write custom method in the repository like below,
public interface BookRepository extends MongoRepository<Book, String> {
Page<Book> findAllByCodeIn(String[] codes, Pageable pageable);
}
you can call the custom method from your service,
bookRepository.findAllByCodeIn(codes, PageRequest.of(0, 10))
I have the below test data inside my db,
bookRepository.save(new Book("S001", "Java"));
bookRepository.save(new Book("S002", "Spring"));
bookRepository.save(new Book("S003", "Kotlin"));
Different test case scenario's
GET http://localhost:8080/books?codes=
{
"content": [],
"pageable": {
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"offset": 0,
"pageNumber": 0,
"pageSize": 10,
"paged": true,
"unpaged": false
},
"totalPages": 0,
"totalElements": 0,
"last": true,
"size": 10,
"number": 0,
"numberOfElements": 0,
"first": true,
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"empty": true
}
Test 2:
GET http://localhost:8080/books?codes=S001
{
"content": [
{
"code": "S001",
"name": "Java"
}
],
Test 3:
GET http://localhost:8080/books?codes=S001,S002
{
"content": [
{
"code": "S001",
"name": "Java"
},
{
"code": "S002",
"name": "Spring"
}
],
I have a huge amount of elasticsearch data, I neeed to make aggregations and return buckets. I need to limit data size returned from elasticsearch to only get a sample for the data not all data.
I have tried adding "size" attribute. But it's not acceptable in bucketing aggregations.
{
"size": 0,
"query": {
"bool": {
"adjust_pure_negative": true,
"boost": 1
}
},
"aggregations": {
"my_agg_1": {
"histogram": {
"field": "coAt",
"interval": 86400,
"offset": 1558216800,
"order": {
"_key": "asc"
},
"keyed": false,
"min_doc_count": 1
},
"aggregations": {
"my_agg_2": {
"terms": {
"field": "atr1",
"missing": "NaN",
"value_type": "string",
"size": 2147483647,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"atr2": {
"top_hits": {
"from": 0,
"size": 1,
"version": false,
"explain": false,
"sort": [
{
"coAt": {
"order": "desc"
}
}
]
}
},
"clientIP_count": {
"value_count": {
"field": "clientIP"
}
}
}
}
}
}
}
}
I am using spring boot 2 and I like the out of the box featured it had, but now I am being asked to reformat to the paging results to a different structure. I would like to continue to use the Pageable and the Page functionality in the controller. I am looking to the proper way to do this.
From the controller
#GetMapping(name = "customers", produces = MediaType.APPLICATION_JSON_VALUE)
Page<Customer> showCustomers(Pageable pageable) {
Page<Customer> page = customerRepo.findCustomers(pageable);
return page;
}
The repo used
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
Here is the default format:
{
"content": [
],
"pageable": {
"sort": {
"sorted": false,
"unsorted": true
},
"offset": 0,
"pageSize": 20,
"pageNumber": 0,
"unpaged": false,
"paged": true
},
"last": false,
"totalPages": 62835,
"totalElements": 1256684,
"size": 20,
"number": 0,
"numberOfElements": 20,
"sort": {
"sorted": false,
"unsorted": true
},
"first": true
}
Here is the format that I want
{
"#id": "/users?page=2&page_size=4",
"#type": "Collection",
"#links": {
"first": {
"href": "/users?page=1&page_size=4"
},
"next": {
"href": "/users?page=3&page_size=4"
},
"previous": {
"href": "/users?page=1&page_size=4"
},
"last": {
"href": "/users?page=5&page_size=4"
}
},
"items": [
Content...
],
"total_items": 20
}
I have a token restful service, which generates the following info when I use postman to hit it (GET).
{
"authorities": [
{
"id": 1,
"authority": "admin"
},
{
"id": 2,
"authority": "ROLE_USER"
}
],
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": null,
"tokenValue": "7760e769-9b1e-4669-8b6d-85e51809934d",
"tokenType": "bearer",
"decodedDetails": null
},
"authenticated": true,
"userAuthentication": {
"authorities": [
{
"id": 1,
"authority": "admin"
},
{
"id": 2,
"authority": "ROLE_USER"
}
],
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": null
},
"authenticated": true,
"principal": {
"id": 1,
"username": "sysadmin",
"password": "$2a$10$xm6.EOh8GrsnwRy91d2cueZPwvPojuExnYEGy1auFyzqYTtdlHvUe",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true,
"authorities": [
{
"id": 1,
"authority": "admin"
},
{
"id": 2,
"authority": "ROLE_USER"
}
],
"userId": "1"
},
"credentials": null,
"name": "sysadmin"
},
"credentials": "",
"oauth2Request": {
"clientId": "movez",
"scope": [
"all"
],
"requestParameters": {
"grant_type": "refresh_token"
},
"resourceIds": [],
"authorities": [],
"approved": true,
"refresh": false,
"redirectUri": null,
"responseTypes": [],
"extensions": {},
"grantType": "refresh_token",
"refreshTokenRequest": null
},
"principal": {
"id": 1,
"username": "sysadmin",
"password": "$2a$10$xm6.EOh8GrsnwRy91d2cueZPwvPojuExnYEGy1auFyzqYTtdlHvUe",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true,
"authorities": [
{
"id": 1,
"authority": "admin"
},
{
"id": 2,
"authority": "ROLE_USER"
}
],
"userId": "1"
},
"clientOnly": false,
"name": "sysadmin"
}
However, when I use RestTemplate exchange to make the api call, I get the following,
The problem here is
There are two layers "authorities", which doesn't match the structure in the Json.
If we go deep, we only have the authority "ROLE_USER", the "admin" is not retrieved.
My code is
Map auth = restTemplate.exchange(tokenVerifyUri, HttpMethod.GET, entity, Map.class).getBody();
It previously worked fine but have this trouble after I upgrade spring to 2.0 (not sure if it is related).
Please help. Thanks in advance.
UPDATE:
If I change Map.class to String.class in exchange function, I got the correct Json.
I have a magento CE 2.1.2 storefront set up. I'd like to use Java to upload products to my store using the Magento REST API. I have managed to get 2 leg OAuth set up using Apache-commons-httpclient, and product upload actually works quite well. The problem comes when I try to upload an image with the product.
From the official catalogProductRepositoryV1 Magento docs, the json syntax is: (the important part being the "media_gallery_entries" bit)
{
"product": {
"id": 0,
"sku": "string",
"name": "string",
"attribute_set_id": 0,
"price": 0,
"status": 0,
"visibility": 0,
"type_id": "string",
"created_at": "string",
"updated_at": "string",
"weight": 0,
"extension_attributes": {
"bundle_product_options": [
{
"option_id": 0,
"title": "string",
"required": true,
"type": "string",
"position": 0,
"sku": "string",
"product_links": [
{
"id": "string",
"sku": "string",
"option_id": 0,
"qty": 0,
"position": 0,
"is_default": true,
"price": 0,
"price_type": 0,
"can_change_quantity": 0,
"extension_attributes": {}
}
],
"extension_attributes": {}
}
],
"downloadable_product_links": [
{
"id": 0,
"title": "string",
"sort_order": 0,
"is_shareable": 0,
"price": 0,
"number_of_downloads": 0,
"link_type": "string",
"link_file": "string",
"link_file_content": {
"file_data": "string",
"name": "string",
"extension_attributes": {}
},
"link_url": "string",
"sample_type": "string",
"sample_file": "string",
"sample_file_content": {
"file_data": "string",
"name": "string",
"extension_attributes": {}
},
"sample_url": "string",
"extension_attributes": {}
}
],
"downloadable_product_samples": [
{
"id": 0,
"title": "string",
"sort_order": 0,
"sample_type": "string",
"sample_file": "string",
"sample_file_content": {
"file_data": "string",
"name": "string",
"extension_attributes": {}
},
"sample_url": "string",
"extension_attributes": {}
}
],
"stock_item": {
"item_id": 0,
"product_id": 0,
"stock_id": 0,
"qty": 0,
"is_in_stock": true,
"is_qty_decimal": true,
"show_default_notification_message": true,
"use_config_min_qty": true,
"min_qty": 0,
"use_config_min_sale_qty": 0,
"min_sale_qty": 0,
"use_config_max_sale_qty": true,
"max_sale_qty": 0,
"use_config_backorders": true,
"backorders": 0,
"use_config_notify_stock_qty": true,
"notify_stock_qty": 0,
"use_config_qty_increments": true,
"qty_increments": 0,
"use_config_enable_qty_inc": true,
"enable_qty_increments": true,
"use_config_manage_stock": true,
"manage_stock": true,
"low_stock_date": "string",
"is_decimal_divided": true,
"stock_status_changed_auto": 0,
"extension_attributes": {}
},
"configurable_product_options": [
{
"id": 0,
"attribute_id": "string",
"label": "string",
"position": 0,
"is_use_default": true,
"values": [
{
"value_index": 0,
"extension_attributes": {}
}
],
"extension_attributes": {},
"product_id": 0
}
],
"configurable_product_links": [
0
]
},
"product_links": [
{
"sku": "string",
"link_type": "string",
"linked_product_sku": "string",
"linked_product_type": "string",
"position": 0,
"extension_attributes": {
"qty": 0
}
}
],
"options": [
{
"product_sku": "string",
"option_id": 0,
"title": "string",
"type": "string",
"sort_order": 0,
"is_require": true,
"price": 0,
"price_type": "string",
"sku": "string",
"file_extension": "string",
"max_characters": 0,
"image_size_x": 0,
"image_size_y": 0,
"values": [
{
"title": "string",
"sort_order": 0,
"price": 0,
"price_type": "string",
"sku": "string",
"option_type_id": 0
}
],
"extension_attributes": {}
}
],
"media_gallery_entries": [
{
"id": 0,
"media_type": "string",
"label": "string",
"position": 0,
"disabled": true,
"types": [
"string"
],
"file": "string",
"content": {
"base64_encoded_data": "string",
"type": "string",
"name": "string"
},
"extension_attributes": {
"video_content": {
"media_type": "string",
"video_provider": "string",
"video_url": "string",
"video_title": "string",
"video_description": "string",
"video_metadata": "string"
}
}
}
],
"tier_prices": [
{
"customer_group_id": 0,
"qty": 0,
"value": 0,
"extension_attributes": {}
}
],
"custom_attributes": [
{
"attribute_code": "string",
"value": "string"
}
]
},
"saveOptions": true
}
The methods I'm running:
public void uploadItem(ItemType item) throws UploadException {
try {
HttpPost postRequest = new HttpPost("http://my.magento.storefront/index.php/rest/V1/products");
postRequest.addHeader("Content-Type", "application/json");
postRequest.addHeader("Authorization", String.format("Bearer %s", authToken));
String jsonItem = itemToJson(item);
System.out.println(jsonItem);
postRequest.setEntity(new StringEntity(jsonItem));
HttpResponse postResponse = httpClient.execute(postRequest);
System.out.println();
System.out.println(EntityUtils.toString(postResponse.getEntity()));
} catch (ParseException | IOException | JSONException e) {
e.printStackTrace();
throw new UploadException(e);
}
}
private String imagesToJson(ItemType item) throws IOException {
String imageUrl = "http://my.image.jpeg"; //pulled from item in production
String encodedImage = null;
URL url = new URL(imageUrl);
try(InputStream in = new BufferedInputStream(url.openStream());
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
byte[] buf = new byte[512];
for (int count = in.read(buf); count >= 0; count = in.read(buf)) {
out.write(buf, 0, count);
}
byte[] response = out.toByteArray(); //sane, I tried saving to a file and checking
encodedImage = Base64.getEncoder().encodeToString(response);
}
String picName = item.getItemID() + ".jpg";
return new JSONArray().put(
new JSONObject()
.put("position", 0)
.put("media_type", "image")
.put("disabled", "false")
.put("types", new JSONArray()
.put("image")
.put("small_image")
.put("thumbnail"))
.put("label", picName)
.put("content", new JSONObject()
.put("base64_encoded_data", encodedImage)
.put("type", "image/jpeg")
.put("name", picName))
).toString();
}
private String itemToJson(ItemType item) throws JSONException, IOException {
return new JSONObject().put("saveOptions", "true").put("product",
new JSONObject()
.put("sku", item.getItemID())
.put("name", item.getTitle())
.put("attribute_set_id", 4)
.put("price", item.getSellingStatus().getCurrentPrice().getValue())
.put("status", 0)
.put("visibility", 0)
.put("type_id", "simple")
.put("weight", item.getShippingDetails().getCalculatedShippingRate().getWeightMajor().getValue())
.put("media_gallery_entries", imagesToJson(item)))
.toString();
}
Using uploadItem(ItemType), the product is uploaded to the catalog. However, there is no image on the store, and I'm given "media_gallery_entries": [] in the response, with no further debugging help!
I think I've implemented everything correctly, so I'm unsure what to do other than SFTP and manually manage the media folder; which just sounds ugly.
Let me know if anyone needs any extra info, or omitted methods/fields.
I solved this by using Gson instead of org.json. I believe the issue was me erroneously using string literals where the server expected otherwise (namely, the boolean values).