Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,6 @@

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>2.20.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
Expand All @@ -114,6 +107,19 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>tools.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>3.0.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Jackson 3.0 requires jackson-annotations 2.20 -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.20</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand All @@ -138,14 +144,6 @@
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
Expand Down Expand Up @@ -196,6 +194,10 @@
<artifactId>commons-lang3</artifactId>
<version>3.19.0</version>
</dependency>
<dependency>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.github.npathai</groupId>
<artifactId>hamcrest-optional</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.kohsuke.github;

import com.fasterxml.jackson.core.JsonProcessingException;
import tools.jackson.core.JacksonException;

import java.io.PrintWriter;
import java.io.StringWriter;
Expand All @@ -20,7 +20,7 @@ class EnterpriseManagedSupport {

static final String TEAM_CANNOT_BE_EXTERNALLY_MANAGED_ERROR = "This team cannot be externally managed since it has explicit members.";

private static String logUnexpectedFailure(final JsonProcessingException exception, final String payload) {
private static String logUnexpectedFailure(final JacksonException exception, final String payload) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
exception.printStackTrace(pw);
Expand Down Expand Up @@ -58,7 +58,7 @@ Optional<GHIOException> filterException(final HttpException he, final String sce
} else if (TEAM_CANNOT_BE_EXTERNALLY_MANAGED_ERROR.equals(error.getMessage())) {
return Optional.of(new GHTeamCannotBeExternallyManagedException(scenario, error, he));
}
} catch (final JsonProcessingException e) {
} catch (final JacksonException e) {
// We can ignore it
LOGGER.warning(() -> logUnexpectedFailure(e, responseMessage));
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/kohsuke/github/GHEventInfo.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.kohsuke.github;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import tools.jackson.databind.node.ObjectNode;

import java.io.IOException;
import java.time.Instant;
Expand Down Expand Up @@ -174,7 +174,7 @@ public GHOrganization getOrganization() throws IOException {
* if payload cannot be parsed
*/
public <T extends GHEventPayload> T getPayload(Class<T> type) throws IOException {
T v = GitHubClient.getMappingObjectReader(root()).readValue(payload.traverse(), type);
T v = GitHubClient.getMappingObjectReader(root()).forType(type).readValue(payload);
v.lateBind();
return v;
}
Expand Down
16 changes: 14 additions & 2 deletions src/main/java/org/kohsuke/github/GHRef.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.kohsuke.github;

import com.fasterxml.jackson.databind.JsonMappingException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import tools.jackson.databind.DatabindException;

import java.io.IOException;
import java.net.URL;
Expand Down Expand Up @@ -59,6 +59,17 @@ public URL getUrl() {
}
}

private static boolean hasDatabindExceptionCause(Throwable e) {
Throwable cause = e;
while (cause != null) {
if (cause instanceof DatabindException) {
return true;
}
cause = cause.getCause();
}
return false;
}

/**
* Retrieve a ref of the given type for the current GitHub repository.
*
Expand Down Expand Up @@ -88,7 +99,8 @@ static GHRef read(GHRepository repository, String refName) throws IOException {
// If the parse exception is due to the above returning an array instead of a single ref
// that means the individual ref did not exist. Handled by result check below.
// Otherwise, rethrow.
if (!(e.getCause() instanceof JsonMappingException)) {
// In Jackson 3, DatabindException is wrapped in IOException, so check the nested cause chain
if (!hasDatabindExceptionCause(e)) {
throw e;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/kohsuke/github/GHRepositoryRule.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.kohsuke.github;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.kohsuke.github.internal.EnumUtils;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.JsonNode;

import java.io.IOException;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.kohsuke.github;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import tools.jackson.databind.exc.MismatchedInputException;

import java.io.IOException;
import java.util.Arrays;
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/kohsuke/github/GitHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
*/
package org.kohsuke.github;

import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.kohsuke.github.authorization.AuthorizationProvider;
import org.kohsuke.github.authorization.ImmutableAuthorizationProvider;
import org.kohsuke.github.authorization.UserAuthorizationProvider;
import org.kohsuke.github.connector.GitHubConnector;
import tools.jackson.databind.ObjectReader;
import tools.jackson.databind.ObjectWriter;

import java.io.*;
import java.util.*;
Expand Down
41 changes: 29 additions & 12 deletions src/main/java/org/kohsuke/github/GitHubClient.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package org.kohsuke.github;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.apache.commons.io.IOUtils;
import org.kohsuke.github.authorization.AuthorizationProvider;
import org.kohsuke.github.authorization.UserAuthorizationProvider;
import org.kohsuke.github.connector.GitHubConnector;
import org.kohsuke.github.connector.GitHubConnectorRequest;
import org.kohsuke.github.connector.GitHubConnectorResponse;
import org.kohsuke.github.function.FunctionThrows;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.InjectableValues;
import tools.jackson.databind.MapperFeature;
import tools.jackson.databind.ObjectReader;
import tools.jackson.databind.ObjectWriter;
import tools.jackson.databind.PropertyNamingStrategies;
import tools.jackson.databind.json.JsonMapper;

import java.io.*;
import java.net.*;
Expand Down Expand Up @@ -109,21 +113,34 @@ static class RetryRequestException extends IOException {
/** The Constant DEFAULT_MINIMUM_RETRY_TIMEOUT_MILLIS. */
private static final int DEFAULT_MINIMUM_RETRY_MILLIS = DEFAULT_MAXIMUM_RETRY_MILLIS;
private static final Logger LOGGER = Logger.getLogger(GitHubClient.class.getName());
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final JsonMapper MAPPER = JsonMapper.builder()
// Use annotations and enable access to private fields
.enable(MapperFeature.USE_ANNOTATIONS)
.enable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)
.enable(MapperFeature.INFER_PROPERTY_MUTATORS)
.enable(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS)
// Set visibility to detect all fields (including private fields)
// This matches the original Jackson 2 config: new VisibilityChecker.Std(NONE, NONE, NONE, NONE, ANY)
.changeDefaultVisibility(vc -> {
return vc.withGetterVisibility(NONE)
.withIsGetterVisibility(NONE)
.withSetterVisibility(NONE)
.withCreatorVisibility(NONE)
.withFieldVisibility(ANY);
})
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
// Jackson 3 enables these by default - disable to match Jackson 2.x behavior
.disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
.propertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
.build();

private static final ThreadLocal<String> sendRequestTraceId = new ThreadLocal<>();

/** The Constant GITHUB_URL. */
static final String GITHUB_URL = "https://api.github.com";

static {
MAPPER.registerModule(new JavaTimeModule());
MAPPER.setVisibility(new VisibilityChecker.Std(NONE, NONE, NONE, NONE, ANY));
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MAPPER.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true);
MAPPER.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
}

@Nonnull
private static <T> GitHubResponse<T> createResponse(@Nonnull GitHubConnectorResponse connectorResponse,
@CheckForNull BodyHandler<T> handler) throws IOException {
Expand Down
13 changes: 6 additions & 7 deletions src/main/java/org/kohsuke/github/GitHubResponse.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
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.connector.GitHubConnectorResponse;
import tools.jackson.core.JacksonException;
import tools.jackson.databind.InjectableValues;

import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -99,10 +98,10 @@ static <T> T parseBody(GitHubConnectorResponse connectorResponse, Class<T> type)
inject.addValue(GitHubConnectorResponse.class, connectorResponse);

return GitHubClient.getMappingObjectReader(connectorResponse).forType(type).readValue(data);
} catch (JsonMappingException | JsonParseException e) {
} catch (JacksonException e) {
String message = "Failed to deserialize: " + data;
LOGGER.log(Level.FINE, message);
throw e;
throw new IOException(message, e);
}
}

Expand All @@ -125,10 +124,10 @@ static <T> T parseBody(GitHubConnectorResponse connectorResponse, T instance) th
String data = getBodyAsString(connectorResponse);
try {
return GitHubClient.getMappingObjectReader(connectorResponse).withValueToUpdate(instance).readValue(data);
} catch (JsonMappingException | JsonParseException e) {
} catch (JacksonException e) {
String message = "Failed to deserialize: " + data;
LOGGER.log(Level.FINE, message);
throw e;
throw new IOException(message, e);
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/test/java/org/kohsuke/github/AotIntegrationTest.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.kohsuke.github;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.node.ArrayNode;

import java.io.IOException;
import java.nio.file.Files;
Expand Down Expand Up @@ -80,7 +80,9 @@ public void testIfAllRequiredClassesAreRegisteredForAot() throws IOException {

private Stream<String> readAotConfigToStreamOfClassNames(String reflectionConfig) throws IOException {
byte[] reflectionConfigFileAsBytes = Files.readAllBytes(Path.of(reflectionConfig));
ArrayNode reflectConfigJsonArray = (ArrayNode) new ObjectMapper().readTree(reflectionConfigFileAsBytes);
ArrayNode reflectConfigJsonArray = (ArrayNode) JsonMapper.builder()
.build()
.readTree(reflectionConfigFileAsBytes);
return StreamSupport
.stream(Spliterators.spliteratorUnknownSize(reflectConfigJsonArray.iterator(), Spliterator.ORDERED),
false)
Expand Down
16 changes: 10 additions & 6 deletions src/test/java/org/kohsuke/github/GHRateLimitTest.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.kohsuke.github;

import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.exc.ValueInstantiationException;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.junit.Test;
import tools.jackson.databind.exc.MismatchedInputException;
import tools.jackson.databind.exc.ValueInstantiationException;

import java.io.IOException;
import java.time.Duration;
Expand Down Expand Up @@ -440,8 +440,10 @@ public void testGitHubRateLimitWithBadData() throws Exception {
fail("Invalid rate limit missing some records should throw");
} catch (Exception e) {
assertThat(e, instanceOf(HttpException.class));
assertThat(e.getCause(), instanceOf(ValueInstantiationException.class));
assertThat(e.getCause().getMessage(),
// In Jackson 3, the exception is wrapped in IOException
assertThat(e.getCause(), instanceOf(IOException.class));
assertThat(e.getCause().getCause(), instanceOf(ValueInstantiationException.class));
assertThat(e.getCause().getCause().getMessage(),
containsString(
"Cannot construct instance of `org.kohsuke.github.GHRateLimit`, problem: `java.lang.NullPointerException`"));
}
Expand All @@ -451,8 +453,10 @@ public void testGitHubRateLimitWithBadData() throws Exception {
fail("Invalid rate limit record missing a value should throw");
} catch (Exception e) {
assertThat(e, instanceOf(HttpException.class));
assertThat(e.getCause(), instanceOf(MismatchedInputException.class));
assertThat(e.getCause().getMessage(),
// In Jackson 3, the exception is wrapped in IOException
assertThat(e.getCause(), instanceOf(IOException.class));
assertThat(e.getCause().getCause(), instanceOf(MismatchedInputException.class));
assertThat(e.getCause().getCause().getMessage(),
containsString("Missing required creator property 'reset' (index 2)"));
}

Expand Down
6 changes: 4 additions & 2 deletions src/test/java/org/kohsuke/github/GHRepositoryTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.kohsuke.github;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.google.common.collect.Sets;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.io.IOUtils;
Expand All @@ -9,6 +8,7 @@
import org.kohsuke.github.GHCheckRun.Conclusion;
import org.kohsuke.github.GHOrganization.RepositoryRole;
import org.kohsuke.github.GHRepository.Visibility;
import tools.jackson.databind.DatabindException;

import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
Expand Down Expand Up @@ -1039,7 +1039,9 @@ public void listRefs() throws Exception {
fail();
} catch (Exception e) {
assertThat(e, instanceOf(HttpException.class));
assertThat(e.getCause(), instanceOf(JsonMappingException.class));
// In Jackson 3, DatabindException is wrapped in IOException
assertThat(e.getCause(), instanceOf(IOException.class));
assertThat(e.getCause().getCause(), instanceOf(DatabindException.class));
}

// git/refs/heads/gh
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.kohsuke.github.connector;

import com.fasterxml.jackson.databind.util.ByteBufferBackedInputStream;
import org.apache.commons.io.IOUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.Assert;
import org.junit.Test;
import org.kohsuke.github.AbstractGitHubWireMockTest;
import org.kohsuke.github.connector.GitHubConnectorResponse.ByteArrayResponse;
import tools.jackson.databind.util.ByteBufferBackedInputStream;

import java.io.ByteArrayInputStream;
import java.io.IOException;
Expand Down
Loading
Loading