How to parse gzip-encoded response using RestTemplate from Spring-Web

After I changed the RESTful web service usage example to call users by id from api.stackexchange.com, I get a JsonParseException:

com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens

The answer from api.stackexchange.com gzip compressed.

How to add gzip compressed response support in Spring-Web RestTemplate?

I am using Spring boot parent ver. 1.3.1.RELEASE hence Spring-Web 4.2.4-RELEASE

Here is my adjusted example:

User.java

 package stackexchange.dto; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; @JsonIgnoreProperties(ignoreUnknown = true) @JsonNaming(LowerCaseWithUnderscoresStrategy.class) public class User { // Properties made public in order to shorten the example public int userId; public String displayName; public int reputation; @Override public String toString() { return "user{" + "display_name='" + displayName + '\'' + "reputation='" + reputation + '\'' + "user_id='" + userId + '\'' + '}'; } } 

CommonWrapper.java

 package stackexchange.dto; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; @JsonIgnoreProperties(ignoreUnknown = true) @JsonNaming(LowerCaseWithUnderscoresStrategy.class) public class CommonWrapper { // Properties made public in order to shorten the example public boolean hasMore; // an array of the type found in type public User[] items; public int page; public int pageSize; public int quotaMax; public int quotaRemaining; @Override public String toString() { StringBuilder sb = new StringBuilder(); for (User user : items) { sb.append("{" + user.toString() + "}\n"); } return "common_wrapper{" + "\"items\"=[\n" + sb + "]" + "has_more='" + hasMore + '\'' + "page='" + page + '\'' + "page_size='" + pageSize + '\'' + "quota_max='" + quotaMax + '\'' + "quota_remaining='" + quotaRemaining + '\'' + '}'; } } 

Stackackchange.java

 package stackexchange; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.web.client.RestTemplate; import stackexchange.dto.CommonWrapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; @JsonNaming(LowerCaseWithUnderscoresStrategy.class) public class StackExchange implements CommandLineRunner{ private static final Logger log = LoggerFactory.getLogger(StackExchange.class); public static void main(String args[]) { SpringApplication.run(StackExchange.class); } @Override public void run(String... strings) throws Exception { RestTemplate restTemplate = new RestTemplate(); CommonWrapper response = restTemplate .getForObject( "https://api.stackexchange.com/2.2/users/4607349?site=stackoverflow", CommonWrapper.class); log.info(response.toString()); } } 

pom.xml - same as in the example

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>stackexchangetest</groupId> <artifactId>stackexchangetest</artifactId> <version>0.0.1</version> <name>stackexchangetest</name> <description>api.stackexchange.com Test</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.1.RELEASE</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 
+9
source share
2 answers

Replace defaultFactory with one of Apache's HttpClient (which decodes GZIP on the fly):

 HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory( HttpClientBuilder.create().build()); RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory); 

Add Apache Http Client to pom.xml

 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <!--Version is not needed when used with Spring Boot parent pom file --> <version>4.5.1</version> </dependency> 
+30
source
 private String callViaRest(String requestString, Steps step) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_XML); headers.add("Accept-Encoding", "application/gzip"); HttpEntity<String> entity = new HttpEntity<String>(requestString, headers); byte[] responseBytes = jsonRestTemplate .exchange("yourUrl", HttpMethod.POST, entity, byte[].class).getBody(); String decompressed = null; try { decompressed= new String(CompressionUtil.decompressGzipByteArray(responseBytes),Charsets.UTF_8); } catch (IOException e) { LOGGER.error("network call failed.", e); } return decompressed; } 
0
source

Source: https://habr.com/ru/post/1238947/


All Articles