Skip to content

Commit

Permalink
feat(TCOMP-2408): all causes of ComponentException are Exception.class (
Browse files Browse the repository at this point in the history
#706)

* feat(TCOMP-2408): all causes of ComponentException are Exception.class

---------

Co-authored-by: Emmanuel GALLOIS <[email protected]>
Co-authored-by: yyin <[email protected]>
Co-authored-by: Axel Catoire <[email protected]>
  • Loading branch information
4 people committed Aug 14, 2024
1 parent d9dfbf0 commit 4386f7c
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public static enum ErrorOrigin {

public ComponentException(final ErrorOrigin errorOrigin, final String type, final String message,
final StackTraceElement[] stackTrace, final Throwable cause) {
super((type != null ? "(" + type + ") " : "") + message, cause);
super((type != null ? "(" + type + ") " : "") + message);
this.initCause(toGenericThrowable(cause));
this.errorOrigin = errorOrigin;
originalType = type;
originalMessage = message;
Expand Down Expand Up @@ -70,4 +71,35 @@ public ComponentException(final Throwable cause) {
this(ErrorOrigin.UNKNOWN, cause.getMessage(), cause);
}

/**
* Convert all exception stack to generic throwable stack to avoid unknown exception at deserialization time..
*
* @param t
* @return An Throwable.
*/
protected Throwable toGenericThrowable(final Throwable t) {
if (t == null) {
return null;
}
if (t instanceof ComponentException) {
return t;
}
Throwable generic = new Throwable(String.format("(%s) : %s", t.getClass().getName(), t.getMessage()));
generic.setStackTrace(t.getStackTrace());

Throwable cause = t.getCause();
Throwable genericCause = null;
if (cause != null) {
genericCause = toGenericThrowable(cause);
} else {
return generic;
}

if (genericCause != null) {
generic = new Throwable(generic.getMessage(), genericCause);
}

return generic;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright (C) 2006-2024 Talend Inc. - www.talend.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.talend.sdk.component.api.exception;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class ComponentExceptionTest {

@Test
void testTypedCauseExceptionTransformation() {
IndexOutOfBoundsException indexOutOfBoundsException = new IndexOutOfBoundsException("AAA");
IllegalArgumentException illegalArgumentException =
new IllegalArgumentException("BBB", indexOutOfBoundsException);
IllegalStateException illegalStateException = new IllegalStateException("CCC", illegalArgumentException);

ComponentException componentException = new ComponentException("DDD", illegalStateException);

Throwable ccc = componentException.getCause();
Assertions.assertEquals(Throwable.class, ccc.getClass());

Throwable bbb = ccc.getCause();
Assertions.assertEquals(Throwable.class, bbb.getClass());

Throwable aaa = bbb.getCause();
Assertions.assertEquals(Throwable.class, aaa.getClass());
}

@Test
void testConstructor() {
ComponentException componentException = new ComponentException("message");
Assertions.assertNull(componentException.getCause());
}

@Test
void testParameters() {
ComponentException componentException = new ComponentException(new IndexOutOfBoundsException("cause"));
Assertions.assertNotNull(componentException.getCause());
Assertions.assertEquals("java.lang.IndexOutOfBoundsException", componentException.getOriginalType());
Assertions.assertEquals(ComponentException.ErrorOrigin.UNKNOWN, componentException.getErrorOrigin());

componentException = new ComponentException(ComponentException.ErrorOrigin.USER, "message");
Assertions.assertEquals(ComponentException.ErrorOrigin.USER, componentException.getErrorOrigin());
}

}
6 changes: 6 additions & 0 deletions sample-parent/sample-connector/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.talend.sdk.component</groupId>
<artifactId>component-runtime-impl</artifactId>
<version>1.65.0M6-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
import java.time.ZonedDateTime;

import org.talend.sdk.component.api.configuration.Option;
import org.talend.sdk.component.api.configuration.ui.DefaultValue;
import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
import org.talend.sdk.component.api.configuration.ui.widget.DateTime;
import org.talend.sdk.component.api.meta.Documentation;

import lombok.Data;

@Data
@GridLayout({
@GridLayout.Row({ "date" }),
@GridLayout.Row({ "dataset" }) })
@GridLayout.Row({ "dataset" }),
@GridLayout.Row({ "generateException" }) })
@GridLayout(
names = GridLayout.FormType.ADVANCED,
value = {
Expand All @@ -43,4 +48,13 @@ public class InputConfig implements Serializable {
@Documentation("Doc: default date documentation without Internationalization.")
private ZonedDateTime date;

@Option
@Documentation("Doc: Use the generate exception service or not.")
@DefaultValue("false")
private Boolean generateException = false;

@Option
@Documentation("Doc: Use the generate runtime exception service or not.")
@DefaultValue("false")
private Boolean generateRuntimeException = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.talend.sdk.component.api.input.Producer;
import org.talend.sdk.component.api.meta.Documentation;
import org.talend.sdk.component.test.connectors.config.InputConfig;
import org.talend.sdk.component.test.connectors.service.GenerateExceptionServices;

@Icon(value = Icon.IconType.CUSTOM, custom = "input")
@Documentation("Doc: default TheInput1 documentation without Internationalization.")
Expand All @@ -41,12 +42,19 @@ public class TheInput1 implements Serializable {

InputConfig config;

public TheInput1(final @Option("configin") InputConfig config) {
private final GenerateExceptionServices exceptionServices;

public TheInput1(final @Option("configin") InputConfig config,
final GenerateExceptionServices exceptionServices) {
this.config = config;
this.exceptionServices = exceptionServices;
}

@PostConstruct
public void init() {
if (config.getGenerateException()) {
exceptionServices.generateException();
}
}

@PreDestroy
Expand All @@ -55,7 +63,9 @@ public void release() {

@Producer
public Object next() {

if (config.getGenerateRuntimeException()) {
exceptionServices.generateRuntimeException();
}
return LocalDate.now();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.talend.sdk.component.api.meta.Documentation;
import org.talend.sdk.component.test.connectors.config.InputConfig;
import org.talend.sdk.component.test.connectors.migration.AbstractMigrationHandler;
import org.talend.sdk.component.test.connectors.service.GenerateExceptionServices;

@Version(value = InputConfig.INPUT_CONFIG_VERSION,
migrationHandler = AbstractMigrationHandler.InputMigrationHandler.class)
Expand All @@ -47,9 +48,12 @@ public class TheMapper1 implements Serializable {

private InputConfig config;

public TheMapper1(final @Option("configin") InputConfig config) {
private final GenerateExceptionServices exceptionServices;

public TheMapper1(final @Option("configin") InputConfig config,
final GenerateExceptionServices exceptionServices) {
this.config = config;
this.exceptionServices = exceptionServices;
}

@Assessor
Expand All @@ -66,7 +70,7 @@ public List<TheMapper1> split(@PartitionSize final int desiredNbSplits) {
@Emitter
public TheInput1 createSource() {

return new TheInput1(this.config);
return new TheInput1(this.config, this.exceptionServices);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Copyright (C) 2006-2024 Talend Inc. - www.talend.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.talend.sdk.component.test.connectors.service;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;

import org.talend.sdk.component.api.exception.ComponentException;
import org.talend.sdk.component.api.service.Service;
import org.talend.sdk.component.runtime.base.lang.exception.InvocationExceptionWrapper;

@Service
public class GenerateExceptionServices implements Serializable {

public void generateException() throws ComponentException {
IndexOutOfBoundsException indexOutOfBoundsException =
new IndexOutOfBoundsException("This is an index out of bound exception");
IllegalArgumentException illegalArgumentException =
new IllegalArgumentException("This is an illegal argument exception", indexOutOfBoundsException);
IllegalStateException illegalStateException =
new IllegalStateException("This is an illegal state exception", illegalArgumentException);
throw new ComponentException("This is component exception", illegalStateException);
}

public void generateRuntimeException() throws ComponentException {
throw InvocationExceptionWrapper
.toRuntimeException(new InvocationTargetException(new CustomException("custom for test")));
}

public static class CustomException extends RuntimeException {

public CustomException(final String message) {
super(message, new AnotherException("other"));
}
}

public static class AnotherException extends RuntimeException {

public AnotherException(final String message) {
super(message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ InputConfig.dataset._displayName = Name: Dataset
InputConfig.dataset._documentation = Doc: The dataset.
InputConfig.date._displayName = Name: Date
InputConfig.date._documentation = Doc: Retrieve only data after the given date.
InputConfig.generateException._displayName = Generate Exception
InputConfig.generateException._documentation = Doc: Use the generate exception service or not.
InputConfig.generateRuntimeException._displayName = Generate Runtime Exception
InputConfig.generateRuntimeException.._documentation = Doc: Use the generate runtime exception service or not.

# Output
OutputConfig._documentation = Doc: The output config for the connector.
Expand Down

0 comments on commit 4386f7c

Please sign in to comment.