mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-10 15:49:57 +00:00
320 lines
9.2 KiB
Java
320 lines
9.2 KiB
Java
package org.kohsuke.github;
|
|
|
|
import com.fasterxml.jackson.core.JsonParseException;
|
|
import com.fasterxml.jackson.databind.InjectableValues;
|
|
import com.fasterxml.jackson.databind.JsonMappingException;
|
|
import org.apache.commons.io.IOUtils;
|
|
import org.kohsuke.github.function.FunctionThrows;
|
|
|
|
import java.io.Closeable;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.InputStreamReader;
|
|
import java.lang.reflect.Array;
|
|
import java.net.HttpURLConnection;
|
|
import java.net.URL;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.TreeMap;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.annotation.CheckForNull;
|
|
import javax.annotation.Nonnull;
|
|
|
|
/**
|
|
* A GitHubResponse
|
|
* <p>
|
|
* A {@link GitHubResponse} generated by from sending a {@link GitHubRequest} to a {@link GitHubClient}.
|
|
* </p>
|
|
*
|
|
* @param <T>
|
|
* the type of the data parsed from the body of a {@link ResponseInfo}.
|
|
*/
|
|
class GitHubResponse<T> {
|
|
|
|
private static final Logger LOGGER = Logger.getLogger(GitHubResponse.class.getName());
|
|
|
|
private final int statusCode;
|
|
|
|
@Nonnull
|
|
private final GitHubRequest request;
|
|
|
|
@Nonnull
|
|
private final Map<String, List<String>> headers;
|
|
|
|
@CheckForNull
|
|
private final T body;
|
|
|
|
GitHubResponse(GitHubResponse<T> response, @CheckForNull T body) {
|
|
this.statusCode = response.statusCode();
|
|
this.request = response.request();
|
|
this.headers = response.headers();
|
|
this.body = body;
|
|
}
|
|
|
|
GitHubResponse(ResponseInfo responseInfo, @CheckForNull T body) {
|
|
this.statusCode = responseInfo.statusCode();
|
|
this.request = responseInfo.request();
|
|
this.headers = responseInfo.headers();
|
|
this.body = body;
|
|
}
|
|
|
|
/**
|
|
* Parses a {@link ResponseInfo} body into a new instance of {@link T}.
|
|
*
|
|
* @param responseInfo
|
|
* response info to parse.
|
|
* @param type
|
|
* the type to be constructed.
|
|
* @param <T>
|
|
* the type
|
|
* @return a new instance of {@link T}.
|
|
* @throws IOException
|
|
* if there is an I/O Exception.
|
|
*/
|
|
@CheckForNull
|
|
static <T> T parseBody(ResponseInfo responseInfo, Class<T> type) throws IOException {
|
|
|
|
if (responseInfo.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) {
|
|
if (type != null && type.isArray()) {
|
|
// no content for array should be empty array
|
|
return type.cast(Array.newInstance(type.getComponentType(), 0));
|
|
} else {
|
|
// no content for object should be null
|
|
return null;
|
|
}
|
|
}
|
|
|
|
String data = responseInfo.getBodyAsString();
|
|
try {
|
|
InjectableValues.Std inject = new InjectableValues.Std();
|
|
inject.addValue(ResponseInfo.class, responseInfo);
|
|
|
|
return GitHubClient.getMappingObjectReader(responseInfo).forType(type).readValue(data);
|
|
} catch (JsonMappingException | JsonParseException e) {
|
|
String message = "Failed to deserialize: " + data;
|
|
LOGGER.log(Level.FINE, message);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses a {@link ResponseInfo} body into a new instance of {@link T}.
|
|
*
|
|
* @param responseInfo
|
|
* response info to parse.
|
|
* @param instance
|
|
* the object to fill with data parsed from body
|
|
* @param <T>
|
|
* the type
|
|
* @return a new instance of {@link T}.
|
|
* @throws IOException
|
|
* if there is an I/O Exception.
|
|
*/
|
|
@CheckForNull
|
|
static <T> T parseBody(ResponseInfo responseInfo, T instance) throws IOException {
|
|
|
|
String data = responseInfo.getBodyAsString();
|
|
try {
|
|
return GitHubClient.getMappingObjectReader(responseInfo).withValueToUpdate(instance).readValue(data);
|
|
} catch (JsonMappingException | JsonParseException e) {
|
|
String message = "Failed to deserialize: " + data;
|
|
LOGGER.log(Level.FINE, message);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The {@link URL} for this response.
|
|
*
|
|
* @return the {@link URL} for this response.
|
|
*/
|
|
@Nonnull
|
|
public URL url() {
|
|
return request.url();
|
|
}
|
|
|
|
/**
|
|
* The {@link GitHubRequest} for this response.
|
|
*
|
|
* @return the {@link GitHubRequest} for this response.
|
|
*/
|
|
@Nonnull
|
|
public GitHubRequest request() {
|
|
return request;
|
|
}
|
|
|
|
/**
|
|
* The status code for this response.
|
|
*
|
|
* @return the status code for this response.
|
|
*/
|
|
public int statusCode() {
|
|
return statusCode;
|
|
}
|
|
|
|
/**
|
|
* The headers for this response.
|
|
*
|
|
* @return the headers for this response.
|
|
*/
|
|
@Nonnull
|
|
public Map<String, List<String>> headers() {
|
|
return headers;
|
|
}
|
|
|
|
/**
|
|
* Gets the value of a header field for this response.
|
|
*
|
|
* @param name
|
|
* the name of the header field.
|
|
* @return the value of the header field, or {@code null} if the header isn't set.
|
|
*/
|
|
@CheckForNull
|
|
public String headerField(String name) {
|
|
String result = null;
|
|
if (headers.containsKey(name)) {
|
|
result = headers.get(name).get(0);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The body of the response parsed as a {@link T}
|
|
*
|
|
* @return body of the response
|
|
*/
|
|
public T body() {
|
|
return body;
|
|
}
|
|
|
|
/**
|
|
* Represents a supplier of results that can throw.
|
|
*
|
|
* @param <T>
|
|
* the type of results supplied by this supplier
|
|
*/
|
|
@FunctionalInterface
|
|
interface BodyHandler<T> extends FunctionThrows<ResponseInfo, T, IOException> {
|
|
}
|
|
|
|
/**
|
|
* Initial response information supplied to a {@link BodyHandler} when a response is initially received and before
|
|
* the body is processed.
|
|
*/
|
|
static abstract class ResponseInfo implements Closeable {
|
|
|
|
private static final Comparator<String> nullableCaseInsensitiveComparator = Comparator
|
|
.nullsFirst(String.CASE_INSENSITIVE_ORDER);
|
|
|
|
private final int statusCode;
|
|
@Nonnull
|
|
private final GitHubRequest request;
|
|
@Nonnull
|
|
private final Map<String, List<String>> headers;
|
|
|
|
protected ResponseInfo(@Nonnull GitHubRequest request,
|
|
int statusCode,
|
|
@Nonnull Map<String, List<String>> headers) {
|
|
this.request = request;
|
|
this.statusCode = statusCode;
|
|
|
|
// Response header field names must be case-insensitive.
|
|
TreeMap<String, List<String>> caseInsensitiveMap = new TreeMap<>(nullableCaseInsensitiveComparator);
|
|
caseInsensitiveMap.putAll(headers);
|
|
|
|
this.headers = Collections.unmodifiableMap(caseInsensitiveMap);
|
|
}
|
|
|
|
/**
|
|
* Gets the value of a header field for this response.
|
|
*
|
|
* @param name
|
|
* the name of the header field.
|
|
* @return the value of the header field, or {@code null} if the header isn't set.
|
|
*/
|
|
@CheckForNull
|
|
public String headerField(String name) {
|
|
String result = null;
|
|
if (headers.containsKey(name)) {
|
|
result = headers.get(name).get(0);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The response body as an {@link InputStream}.
|
|
*
|
|
* @return the response body
|
|
* @throws IOException
|
|
* if an I/O Exception occurs.
|
|
*/
|
|
abstract InputStream bodyStream() throws IOException;
|
|
|
|
/**
|
|
* The error message for this response.
|
|
*
|
|
* @return if there is an error with some error string, that is returned. If not, {@code null}.
|
|
*/
|
|
abstract String errorMessage();
|
|
|
|
/**
|
|
* The {@link URL} for this response.
|
|
*
|
|
* @return the {@link URL} for this response.
|
|
*/
|
|
@Nonnull
|
|
public URL url() {
|
|
return request.url();
|
|
}
|
|
|
|
/**
|
|
* Gets the {@link GitHubRequest} for this response.
|
|
*
|
|
* @return the {@link GitHubRequest} for this response.
|
|
*/
|
|
@Nonnull
|
|
public GitHubRequest request() {
|
|
return request;
|
|
}
|
|
|
|
/**
|
|
* The status code for this response.
|
|
*
|
|
* @return the status code for this response.
|
|
*/
|
|
public int statusCode() {
|
|
return statusCode;
|
|
}
|
|
|
|
/**
|
|
* The headers for this response.
|
|
*
|
|
* @return the headers for this response.
|
|
*/
|
|
@Nonnull
|
|
public Map<String, List<String>> headers() {
|
|
return headers;
|
|
}
|
|
|
|
/**
|
|
* Gets the body of the response as a {@link String}.
|
|
*
|
|
* @return the body of the response as a {@link String}.
|
|
* @throws IOException
|
|
* if an I/O Exception occurs.
|
|
*/
|
|
@Nonnull
|
|
String getBodyAsString() throws IOException {
|
|
InputStreamReader r = null;
|
|
r = new InputStreamReader(this.bodyStream(), StandardCharsets.UTF_8);
|
|
return IOUtils.toString(r);
|
|
}
|
|
}
|
|
|
|
}
|