diff --git a/org.eclipse.buildship.core.test/src/main/groovy/org/eclipse/buildship/core/internal/marker/GradleMarkerManagerTest.groovy b/org.eclipse.buildship.core.test/src/main/groovy/org/eclipse/buildship/core/internal/marker/GradleMarkerManagerTest.groovy index 6602b8aac..b88b734f4 100644 --- a/org.eclipse.buildship.core.test/src/main/groovy/org/eclipse/buildship/core/internal/marker/GradleMarkerManagerTest.groovy +++ b/org.eclipse.buildship.core.test/src/main/groovy/org/eclipse/buildship/core/internal/marker/GradleMarkerManagerTest.groovy @@ -104,6 +104,24 @@ class GradleMarkerManagerTest extends ProjectSynchronizationSpecification { gradleErrorMarkers[0].resource.fullPath.toPortableString() == '/' } + def "Long error messages are trimmed"() { + setup: + GradleMarkerManager.addError(gradleBuild, problemWithLongMessage) + + expect: + numOfGradleErrorMarkers == 1 + (gradleErrorMarkers[0].getAttribute(IMarker.MESSAGE) as String).length() == 65535 + } + + def "Long stacktraces are trimmed"() { + setup: + GradleMarkerManager.addError(gradleBuild, problemWithLongStacktrace) + + expect: + numOfGradleErrorMarkers == 1 + (gradleErrorMarkers[0].getAttribute(GradleErrorMarker.ATTRIBUTE_STACKTRACE) as String).length() == 65535 + } + private InternalGradleBuild getGradleBuild() { GradleCore.workspace.getBuild(project).get(); } @@ -119,4 +137,20 @@ class GradleMarkerManagerTest extends ProjectSynchronizationSpecification { private ToolingApiStatus getConnectionProblem() { ToolingApiStatus.from("", new GradleConnectionException('')) } + + private ToolingApiStatus getProblemWithLongMessage() { + ToolingApiStatus.from("", new GradleConnectionException('X' * 70000)) + } + + private ToolingApiStatus getProblemWithLongStacktrace() { + ToolingApiStatus.from("", createException(400)) + } + + private Throwable createException(int numOfRootCauses) { + if (numOfRootCauses == 0) { + return new GradleConnectionException("") + } else { + return new GradleConnectionException("", createException(numOfRootCauses - 1)) + } + } } diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/marker/GradleErrorMarker.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/marker/GradleErrorMarker.java index 1d05eec2b..09312a950 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/marker/GradleErrorMarker.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/marker/GradleErrorMarker.java @@ -9,6 +9,8 @@ ******************************************************************************/ package org.eclipse.buildship.core.internal.marker; +import java.nio.charset.StandardCharsets; + import com.google.common.base.Throwables; import org.eclipse.core.resources.IMarker; @@ -53,16 +55,35 @@ private static void createMarker(int severity, IResource resource, InternalGradl marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); } - marker.setAttribute(IMarker.MESSAGE, message); + marker.setAttribute(IMarker.MESSAGE, trimMarkerProperty(message)); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); marker.setAttribute(IMarker.SEVERITY, severity); marker.setAttribute(ATTRIBUTE_ROOT_DIR, gradleBuild.getBuildConfig().getRootProjectDirectory().getAbsolutePath()); if (exception != null) { String stackTrace = Throwables.getStackTraceAsString(exception); - marker.setAttribute(GradleErrorMarker.ATTRIBUTE_STACKTRACE, stackTrace); + marker.setAttribute(GradleErrorMarker.ATTRIBUTE_STACKTRACE, trimMarkerProperty(stackTrace)); } } catch (CoreException e) { CorePlugin.logger().warn("Cannot create Gradle error marker", e); } } + + /* + * The Eclipse platform will throw an exception if a marker property is longer than 65535 bytes + * https://github.com/eclipse-platform/eclipse.platform/blob/97d555a8b563dcb3a32bd43ad58ba452fa027a73/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/MarkerInfo.java#L56-L60 + */ + private static String trimMarkerProperty(String property) { + // avoid calling String.toBytes() for shorter Strings + // UTF-8 can theoretically use up to 4 bytes to represent a code point + if (property.length() < 16384) { + return property; + } + // check precise length + byte[] bytes = property.getBytes(StandardCharsets.UTF_8); + if (bytes.length <= 65535) { + return property; + } + // trim to size if needed + return new String(bytes, 0, 65535, StandardCharsets.UTF_8); + } }