I am reading data from json file, And i want to do a get items by categories
public List<Item> getItemsByCategory(String category) {
List<Item> matchingCategory = new ArrayList<>();
for (Item item : books.getItems()) {
List<String> categories1 = item.getVolumeInfo().getCategories();
// categories1 == null for the first item so the below for loop fails
for (String cat : categories1) {
if (cat.equals(category)) {
matchingCategory.add(item);
} else throw new MyResourceNotFoundException(String.format("category with type %s is not found"));
}
}
return matchingCategory;
}
My first item in th json file has no category this is why categories is null in the first loop , How can i skip it and continue in the item in the json file , Instead of getting null pointer exception
I tried using break but it ends the loop without starting next one
This is my json im reading data from here.
{
"requestedUrl": "https://www.googleapis.com/books/v1/volumes?q=java&maxResults=40",
"items": [
{
"kind": "books#volume",
"id": "7tkN1CYzn2cC",
"etag": "pfjjxSpetIM",
"selfLink": "https://www.googleapis.com/books/v1/volumes/7tkN1CYzn2cC",
"volumeInfo": {
"title": "A Hypervista of the Java Landscape",
"publisher": "InfoStrategist.com",
"industryIdentifiers": [
{
"type": "ISBN_13",
"identifier": "9781592432172"
},
{
"type": "ISBN_10",
"identifier": "1592432174"
}
],
"readingModes": {
"text": true,
"image": true
},
"printType": "BOOK",
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "1.0.1.0.preview.3",
"imageLinks": {
"smallThumbnail": "http://books.google.com/books/content?id=7tkN1CYzn2cC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
"thumbnail": "http://books.google.com/books/content?id=7tkN1CYzn2cC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
},
"language": "en",
"previewLink": "http://books.google.pl/books?id=7tkN1CYzn2cC&pg=PP1&dq=java&hl=&cd=1&source=gbs_api",
"infoLink": "http://books.google.pl/books?id=7tkN1CYzn2cC&dq=java&hl=&source=gbs_api",
"canonicalVolumeLink": "https://books.google.com/books/about/A_Hypervista_of_the_Java_Landscape.html?hl=&id=7tkN1CYzn2cC"
},
"saleInfo": {
"country": "PL",
"saleability": "NOT_FOR_SALE",
"isEbook": false
},
"accessInfo": {
"country": "PL",
"viewability": "PARTIAL",
"embeddable": true,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": true,
"acsTokenLink": "http://books.google.pl/books/download/A_Hypervista_of_the_Java_Landscape-sample-epub.acsm?id=7tkN1CYzn2cC&format=epub&output=acs4_fulfillment_token&dl_type=sample&source=gbs_api"
},
"pdf": {
"isAvailable": true,
"acsTokenLink": "http://books.google.pl/books/download/A_Hypervista_of_the_Java_Landscape-sample-pdf.acsm?id=7tkN1CYzn2cC&format=pdf&output=acs4_fulfillment_token&dl_type=sample&source=gbs_api"
},
"webReaderLink": "http://play.google.com/books/reader?id=7tkN1CYzn2cC&hl=&printsec=frontcover&source=gbs_api",
"accessViewStatus": "SAMPLE",
"quoteSharingAllowed": false
}
},
{
"kind": "books#volume",
"id": "-SYM4PW-YAgC",
"etag": "dXytGSDckJk",
"selfLink": "https://www.googleapis.com/books/v1/volumes/-SYM4PW-YAgC",
"volumeInfo": {
"title": "The Religion of Java",
"authors": [
"Clifford Geertz"
],
"publisher": "University of Chicago Press",
"publishedDate": "1976-02-15",
"description": "Written with a rare combination of analysis and speculation, this comprehensive study of Javanese religion is one of the few books on the religion of a non-Western people which emphasizes variation and conflict in belief as well as similarity and harmony. The reader becomes aware of the intricacy and depth of Javanese spiritual life and the problems of political and social integration reflected in the religion. The Religion of Java will interest specialists in Southeast Asia, anthropologists and sociologists concerned with the social analysis of religious belief and ideology, students of comparative religion, and civil servants dealing with governmental policy toward Indonesia and Southeast Asia.",
"industryIdentifiers": [
{
"type": "ISBN_10",
"identifier": "0226285103"
},
{
"type": "ISBN_13",
"identifier": "9780226285108"
}
],
"readingModes": {
"text": true,
"image": true
},
"pageCount": 392,
"printType": "BOOK",
"categories": [
"Religion"
],
"averageRating": 4.0,
"ratingsCount": 4,
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "2.1.2.0.preview.3",
"imageLinks": {
"smallThumbnail": "http://books.google.com/books/content?id=-SYM4PW-YAgC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
"thumbnail": "http://books.google.com/books/content?id=-SYM4PW-YAgC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
},
"language": "en",
"previewLink": "http://books.google.pl/books?id=-SYM4PW-YAgC&printsec=frontcover&dq=java&hl=&cd=2&source=gbs_api",
"infoLink": "http://books.google.pl/books?id=-SYM4PW-YAgC&dq=java&hl=&source=gbs_api",
"canonicalVolumeLink": "https://books.google.com/books/about/The_Religion_of_Java.html?hl=&id=-SYM4PW-YAgC"
},
"saleInfo": {
"country": "PL",
"saleability": "NOT_FOR_SALE",
"isEbook": false
},
"accessInfo": {
"country": "PL",
"viewability": "PARTIAL",
"embeddable": true,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": true,
"acsTokenLink": "http://books.google.pl/books/download/The_Religion_of_Java-sample-epub.acsm?id=-SYM4PW-YAgC&format=epub&output=acs4_fulfillment_token&dl_type=sample&source=gbs_api"
},
"pdf": {
"isAvailable": false
},
"webReaderLink": "http://play.google.com/books/reader?id=-SYM4PW-YAgC&hl=&printsec=frontcover&source=gbs_api",
"accessViewStatus": "SAMPLE",
"quoteSharingAllowed": false
},
"searchInfo": {
"textSnippet": "Written with a rare combination of analysis and speculation, this comprehensive study of Javanese religion is one of the few books on the religion of a non-Western people which emphasizes variation and conflict in belief as well as ..."
}
} etc
As above the first item has no category but the second does so i should be able to get the second it
Here is what i have done , Using continue and break as well, But i had to remove my exception handler,
public List<Item> getItemsByCategory(String category) {
List<Item> matchingCategory = new ArrayList<>();
for (Item item : books.getItems()) {
List<String> categories1 = item.getVolumeInfo().getCategories();
if(categories1 == null) continue;
for (String cat : categories1) {
if (cat.equals(category)) {
matchingCategory.add(item);
} else break; //throw new MyResourceNotFoundException(String.format("category with type %s is not found", category));
}
}
return matchingCategory;
}
How can i put back the throw new Exception
Why can’t you add an condition..?
if(categories1 != null) {
for() {
...
}
}
Related
I have a collection which name called 'airport' and i have Atlas Auto Complete index you can see JSON config below.
{
"mappings": {
"dynamic": false,
"fields": {
"name": [
{
"type": "string"
},
{
"foldDiacritics": false,
"maxGrams": 7,
"minGrams": 2,
"type": "autocomplete"
}
]
}
}
}
and this is my Document record
{
"_id": {
"$oid": "63de588c7154cc3ee5cbabb2"
},
"name": "Antalya Airport",
"code": "AYT",
"country": "TR",
"createdDate": {
"$date": {
"$numberLong": "1675516044323"
}
},
"updatedDate": {
"$date": {
"$numberLong": "1675516044323"
}
},
"updatedBy": "VISITOR",
"createdBy": "VISITOR",
}
And This is my MongoDB Query
public List<Document> autoCompleteAirports(AutoCompleteRequest autoCompleteRequest) {
return database.getCollection(AIRPORT).aggregate(
Arrays.asList(new Document("$search",
new Document("index", "airportAutoCompleteIndex")
.append("text",
new Document("query", autoCompleteRequest.getKeyword())
.append("path", "name")
)))
).into(new ArrayList<>());
}
So, when i type "antalya" or "Antalya", this works. But when i type "Antaly" or "antal" there is no result.
Any solution ?
i tried change min and max grams settings on index
I'm trying to perform a field sort on the specified field but to no avail. The query keeps returning the same position when I run the script.
Here is the ElasticSearch script:
{
"from": 0,
"size": 10,
"timeout": "60s",
"query": {
"bool": {
"must": [
{
"bool": {
"must": [
{
"query_string": {
"query": "random",
"fields": [],
"type": "best_fields",
"default_operator": "or",
"max_determinized_states": 10000,
"enable_position_increments": true,
"fuzziness": "AUTO",
"fuzzy_prefix_length": 0,
"fuzzy_max_expansions": 50,
"phrase_slop": 0,
"escape": false,
"auto_generate_synonyms_phrase_query": true,
"fuzzy_transpositions": true,
"boost": 1
}
},
{
"nested": {
"query": {
"bool": {
"must": [
{
"match": {
"reviews.source": {
"query": "TEST",
"operator": "AND",
"prefix_length": 0,
"max_expansions": 50,
"fuzzy_transpositions": true,
"lenient": false,
"zero_terms_query": "NONE",
"auto_generate_synonyms_phrase_query": true,
"boost": 1
}
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
},
"path": "reviews",
"ignore_unmapped": false,
"score_mode": "avg",
"boost": 1,
"inner_hits": {
"name": "reviews",
"ignore_unmapped": false,
"from": 0,
"size": 3,
"version": false,
"seq_no_primary_term": false,
"explain": false,
"track_scores": false
}
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
}
],
"should": [
{
"match": {
"dataset": {
"query": "QUERY_TEST",
"operator": "OR",
"prefix_length": 0,
"max_expansions": 50,
"fuzzy_transpositions": true,
"lenient": false,
"zero_terms_query": "NONE",
"auto_generate_synonyms_phrase_query": true,
"boost": 1
}
}
}
],
"adjust_pure_negative": true,
"minimum_should_match": "1",
"boost": 1
}
},
"sort": [
{
"_score": {
"order": "desc"
}
},
{
"reviews.openedAt": {
"order": "desc",
"nested": {
"path": "reviews"
}
}
}
]
}
The mapping I'm currently using:
"reviews": {
"type": "nested",
"properties": {
"id": {
"type": "keyword",
"copy_to": "fulltext"
},
"updatedAt": {
"type": "date",
"format": "strict_date_time",
"index": false
},
"openedAt": {
"type": "date",
"format": "strict_date_time"
}
I'm trying to sort the records based on a specific date in the reviews section. If a user inputs ASC, the returning values (reviews) should be in ascending order based on the openedAt date. I believe the sorting function isn't necessarily hitting the appropriate path. What should the sorting function look like?
I have a Java API that I created that calls the request and creates its own set of records:
public SearchResponse(SearchResponse response, SearchRequest searchRequest) {
this.facets = new ArrayList<>();
if (searchRequest == null || searchRequest.getRestricted().isEmpty()) {
this.records =
Stream.of(response.getHits().getHits()).map(SearchHit::getSourceAsMap).collect(Collectors.toList());
} else {
this.records = processRestrictedResults(response, searchRequest);
}
if (response.getAggregations() != null) {
for (Map.Entry<String, Aggregation> entry : response.getAggregations().getAsMap().entrySet()) {
this.facets.add(Facet.create(entry));
}
}
this.totalRecords = getTotalMatched(response);
}
To answer the original question, the top-level hits are indeed being sorted by the latest reviews.openedAt in the descending order — one of the reviews from doc#2 has the value 2021-04-06T08:13:53.552Z which is greater than the only reviews.openedAt from doc#1 (2021-03-30T08:13:53.552Z), thus #2 comes before #1.
What you're missing, though, is sorted inner_hits, as I explained here and here.
In your particular use case this would mean:
{
"from": 0,
"size": 10,
"timeout": "60s",
"query": {
"bool": {
"must": [
... // your original queries
{
"nested": {
"path": "reviews", <-- we need to enforce the nested context
"query": {
"match_all": {} <-- this could've been `"exists": { "field": "reviews.openedAt" }` too
},
"inner_hits": {
"sort": {
"reviews.openedAt": { <-- sorting the inner hits under the nested context
"order": "desc"
}
}
}
}
}
]
}
},
"sort": [
{
"_score": {
"order": "desc"
}
},
{
"reviews.openedAt": { <-- sorting the top-level hits, as you previously were
"order": "desc",
"nested": {
"path": "reviews"
}
}
}
]
}
When you run the above query, each top-level hit will include an inner_hits attribute containing the sorted reviews which you can then post-process in your java backend.
How to create n number of instances in GCP using rest api.
in AWS java SDK, there is a method withMaxCount where we specify number of ec2 instances.
Similarly is there anything for GCP compute.
You can use REST API in loop to create instances.
Example request will look something like this:
{
"kind": "compute#instance",
"name": "INSTANCE-NAME",
"zone": "projects/PROJECT-NAME/zones/us-central1-a",
"machineType": "projects/PROJECT-NAME/zones/us-central1-a/machineTypes/e2-medium",
"displayDevice": {
"enableDisplay": false
},
"metadata": {
"kind": "compute#metadata",
"items": []
},
"tags": {
"items": []
},
"disks": [
{
"kind": "compute#attachedDisk",
"type": "PERSISTENT",
"boot": true,
"mode": "READ_WRITE",
"autoDelete": true,
"deviceName": "INSTANCE-NAME",
"initializeParams": {
"sourceImage": "projects/debian-cloud/global/images/debian-10-buster-v20210122",
"diskType": "projects/PROJECT-NAME/zones/us-central1-a/diskTypes/pd-standard",
"diskSizeGb": "10",
"labels": {}
},
"diskEncryptionKey": {}
}
],
"canIpForward": false,
"networkInterfaces": [
{
"kind": "compute#networkInterface",
"subnetwork": "regions/us-central1/subnetworks/default",
"accessConfigs": [
{
"kind": "compute#accessConfig",
"name": "External NAT",
"type": "ONE_TO_ONE_NAT",
"networkTier": "PREMIUM"
}
],
"aliasIpRanges": []
}
],
"description": "",
"labels": {},
"scheduling": {
"preemptible": false,
"onHostMaintenance": "MIGRATE",
"automaticRestart": true,
"nodeAffinities": []
},
"deletionProtection": false,
"reservationAffinity": {
"consumeReservationType": "ANY_RESERVATION"
},
"serviceAccounts": [
{
"email": "111111111111-compute#developer.gserviceaccount.com",
"scopes": [
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/trace.append"
]
}
],
"shieldedInstanceConfig": {
"enableSecureBoot": false,
"enableVtpm": true,
"enableIntegrityMonitoring": true
},
"confidentialInstanceConfig": {
"enableConfidentialCompute": false
}
}
Replace it with your own project name and service account, and you can test it here.
I am trying to get the current status of a flight from a 3rd party API. I just need very few fields from the JSON. If I do it in the traditional way I would have to create many classes. And, map the json to the classes. Is there a better way of doing it. In the JSON response,I just need the information in the FlightStatuses field.
{
"request": {
"airline": {
"fsCode": "AA",
"requestedCode": "AA"
},
"flight": {
"requested": "100",
"interpreted": "100"
},
"utc": {
"requested": "false",
"interpreted": false
},
"url": "https://api.flightstats.com/flex/flightstatus/rest/v2/json/flight/status/AA/100/dep/2019/10/1?utc=false",
"nonstopOnly": {
"interpreted": false
},
"date": {
"year": "2019",
"month": "10",
"day": "1",
"interpreted": "2019-10-01"
}
},
"appendix": {
"airlines": [
{
"fs": "AA",
"iata": "AA",
"icao": "AAL",
"name": "American Airlines",
"phoneNumber": "08457-567-567",
"active": true
},
{
"fs": "AY",
"iata": "AY",
"icao": "FIN",
"name": "Finnair",
"phoneNumber": "+ 358 600 140 140",
"active": true
},
{
"fs": "IB",
"iata": "IB",
"icao": "IBE",
"name": "Iberia",
"phoneNumber": "1800 772 4642",
"active": true
},
{
"fs": "LY",
"iata": "LY",
"icao": "ELY",
"name": "El Al",
"phoneNumber": "+ 972-3-9771111",
"active": true
},
{
"fs": "BA",
"iata": "BA",
"icao": "BAW",
"name": "British Airways",
"phoneNumber": "1-800-AIRWAYS",
"active": true
},
{
"fs": "GF",
"iata": "GF",
"icao": "GFA",
"name": "Gulf Air",
"phoneNumber": "973 17 335 777",
"active": true
}
],
"airports": [
{
"fs": "LHR",
"iata": "LHR",
"icao": "EGLL",
"faa": "",
"name": "London Heathrow Airport",
"city": "London",
"cityCode": "LON",
"stateCode": "EN",
"countryCode": "GB",
"countryName": "United Kingdom",
"regionName": "Europe",
"timeZoneRegionName": "Europe/London",
"weatherZone": "",
"localTime": "2019-10-01T15:25:25.492",
"utcOffsetHours": 1.0,
"latitude": 51.469603,
"longitude": -0.453566,
"elevationFeet": 80,
"classification": 1,
"active": true,
"weatherUrl": "https://api.flightstats.com/flex/weather/rest/v1/json/all/LHR?codeType=fs",
"delayIndexUrl": "https://api.flightstats.com/flex/delayindex/rest/v1/json/airports/LHR?codeType=fs"
},
{
"fs": "JFK",
"iata": "JFK",
"icao": "KJFK",
"faa": "JFK",
"name": "John F. Kennedy International Airport",
"street1": "JFK Airport",
"city": "New York",
"cityCode": "NYC",
"stateCode": "NY",
"postalCode": "11430",
"countryCode": "US",
"countryName": "United States",
"regionName": "North America",
"timeZoneRegionName": "America/New_York",
"weatherZone": "NYZ178",
"localTime": "2019-10-01T10:25:25.493",
"utcOffsetHours": -4.0,
"latitude": 40.642335,
"longitude": -73.78817,
"elevationFeet": 13,
"classification": 1,
"active": true,
"weatherUrl": "https://api.flightstats.com/flex/weather/rest/v1/json/all/JFK?codeType=fs",
"delayIndexUrl": "https://api.flightstats.com/flex/delayindex/rest/v1/json/airports/JFK?codeType=fs"
}
],
"equipments": [
{
"iata": "77W",
"name": "Boeing 777-300ER",
"turboProp": false,
"jet": true,
"widebody": true,
"regional": false
}
]
},
"flightStatuses": [
{
"flightId": 1016157813,
"carrierFsCode": "AA",
"flightNumber": "100",
"departureAirportFsCode": "JFK",
"arrivalAirportFsCode": "LHR",
"departureDate": {
"dateUtc": "2019-10-01T22:15:00.000Z",
"dateLocal": "2019-10-01T18:15:00.000"
},
"arrivalDate": {
"dateUtc": "2019-10-02T05:20:00.000Z",
"dateLocal": "2019-10-02T06:20:00.000"
},
"status": "S",
"schedule": {
"flightType": "J",
"serviceClasses": "RFJY",
"restrictions": "",
"uplines": [],
"downlines": []
},
"operationalTimes": {
"publishedDeparture": {
"dateUtc": "2019-10-01T22:15:00.000Z",
"dateLocal": "2019-10-01T18:15:00.000"
},
"scheduledGateDeparture": {
"dateUtc": "2019-10-01T22:15:00.000Z",
"dateLocal": "2019-10-01T18:15:00.000"
},
"estimatedGateDeparture": {
"dateUtc": "2019-10-01T22:15:00.000Z",
"dateLocal": "2019-10-01T18:15:00.000"
},
"publishedArrival": {
"dateUtc": "2019-10-02T05:20:00.000Z",
"dateLocal": "2019-10-02T06:20:00.000"
},
"scheduledGateArrival": {
"dateUtc": "2019-10-02T05:20:00.000Z",
"dateLocal": "2019-10-02T06:20:00.000"
},
"estimatedGateArrival": {
"dateUtc": "2019-10-02T05:20:00.000Z",
"dateLocal": "2019-10-02T06:20:00.000"
}
},
"codeshares": [
{
"fsCode": "AY",
"flightNumber": "4012",
"relationship": "L"
},
{
"fsCode": "BA",
"flightNumber": "1511",
"relationship": "L"
},
{
"fsCode": "GF",
"flightNumber": "6654",
"relationship": "L"
},
{
"fsCode": "IB",
"flightNumber": "4218",
"relationship": "L"
},
{
"fsCode": "LY",
"flightNumber": "8051",
"relationship": "L"
}
],
"delays": {},
"flightDurations": {
"scheduledBlockMinutes": 425
},
"airportResources": {
"departureTerminal": "8",
"departureGate": "16",
"arrivalTerminal": "3"
},
"flightEquipment": {
"scheduledEquipmentIataCode": "77W",
"actualEquipmentIataCode": "77W",
"tailNumber": "N730AN"
}
}
]
}
You can parse your JSON as JsonNode.
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree("[your JSON here]");
After that get only fields, which you need. For example:
jsonNode.get("request").get("airline").get("requestedCode").asText()
Google's Gson could be used to get Json's Object, Array and other Wrapper class from Object.
Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(flightObject);
JsonArray jsonArray = jsonElement.getAsJsonObject().get("flightStatuses").getAsJsonArray();
System.out.println(gson.toJson(jsonArray));
You can just use an object with flightStatuses and ignore the rest essentially;
public class FlightStatusContainer {
private List<FlightStatus> flightStatuses;
// getter & setters
}
If you need only some parts of each FlightStatus object, you can ignore those fields as well in that object. For example let's say that you only need status;
public class FlightStatus {
private String status;
// getter & setters
}
and use these in your 3rd party API call (e.g. with RestTemplate);
FlightStatusContainer fsc = restTemplate.getForObject(targetUrl, FlightStatusContainer.class);
// can use fsc.getFlightStatuses(), and the rest is ignored
will get you a super simplified result;
{
"flightStatuses": [
{
"status": "S"
},
{
"status": "P"
}
]
}
I have nested Json file, I would like to read specific objects from Json file using request methods. Mostly to make exacly endpoints I need. I'm trying even to read everything but it doesn't work.
So I need help with this, I mean how to read whole Json file, after that I think I can handle to make endpoints like I need :
/api/category/{categoryName}/books
I arleady tried something like this :
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
Object getBeers() {
ClassPathResource resource = new ClassPathResource("static/books.json");
try {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(resource.getInputStream(), Object.class);
} catch (IOException e) {
e.printStackTrace();
}
return null; //also tried with path here
}
I have results like this:
(java.io.FileNotFoundException: class path resource [static/books.json] cannot be opened because it does not exist)
I tried write path in all other ways. Not working.
So I'm guessing I'm not doin' it right
Here is whole json if someone needs it:
https://pastebin.com/yruFS5SM
Below is part of my Json, after that it's repeating with similar objects.
{
"requestedUrl": "https://www.googleapis.com/books/v1/volumes?q=java&maxResults=40",
"items": [
{
"kind": "books#volume",
"id": "7tkN1CYzn2cC",
"etag": "pfjjxSpetIM",
"selfLink": "https://www.googleapis.com/books/v1/volumes/7tkN1CYzn2cC",
"volumeInfo": {
"title": "A Hypervista of the Java Landscape",
"publisher": "InfoStrategist.com",
"industryIdentifiers": [
{
"type": "ISBN_13",
"identifier": "9781592432172"
},
{
"type": "ISBN_10",
"identifier": "1592432174"
}
],
"readingModes": {
"text": true,
"image": true
},
"printType": "BOOK",
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "1.0.1.0.preview.3",
"imageLinks": {
"smallThumbnail": "http://books.google.com/books/content?id=7tkN1CYzn2cC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
"thumbnail": "http://books.google.com/books/content?id=7tkN1CYzn2cC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
},
"language": "en",
"previewLink": "http://books.google.pl/books?id=7tkN1CYzn2cC&pg=PP1&dq=java&hl=&cd=1&source=gbs_api",
"infoLink": "http://books.google.pl/books?id=7tkN1CYzn2cC&dq=java&hl=&source=gbs_api",
"canonicalVolumeLink": "https://books.google.com/books/about/A_Hypervista_of_the_Java_Landscape.html?hl=&id=7tkN1CYzn2cC"
},
"saleInfo": {
"country": "PL",
"saleability": "NOT_FOR_SALE",
"isEbook": false
},
"accessInfo": {
"country": "PL",
"viewability": "PARTIAL",
"embeddable": true,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": true,
"acsTokenLink": "http://books.google.pl/books/download/A_Hypervista_of_the_Java_Landscape-sample-epub.acsm?id=7tkN1CYzn2cC&format=epub&output=acs4_fulfillment_token&dl_type=sample&source=gbs_api"
},
"pdf": {
"isAvailable": true,
"acsTokenLink": "http://books.google.pl/books/download/A_Hypervista_of_the_Java_Landscape-sample-pdf.acsm?id=7tkN1CYzn2cC&format=pdf&output=acs4_fulfillment_token&dl_type=sample&source=gbs_api"
},
"webReaderLink": "http://play.google.com/books/reader?id=7tkN1CYzn2cC&hl=&printsec=frontcover&source=gbs_api",
"accessViewStatus": "SAMPLE",
"quoteSharingAllowed": false
}
}