Skip to content

Commit e35e406

Browse files
authored
using the context class loader of the current thread. (#20)
* using the context class loader of the current thread. * fixed record PMD error
1 parent 44dafd8 commit e35e406

File tree

6 files changed

+85
-15
lines changed

6 files changed

+85
-15
lines changed

core/src/main/java/org/sterl/spring/persistent_tasks/api/task/PersistentTask.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,5 @@ default boolean isTransactional() {
6666
* @param e the exception reason - could also be a {@link FailTaskNoRetryException}
6767
* @see <a href="https://spring-persistent-task.sterl.org/failed-spring-triggers/">Failed trigger</a>
6868
*/
69-
default void afterTriggerFailed(@Nullable T state, Exception e) {
70-
}
69+
default void afterTriggerFailed(@Nullable T state, Exception e) {}
7170
}

core/src/main/java/org/sterl/spring/persistent_tasks/shared/converter/ToTrigger.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
import org.sterl.spring.persistent_tasks.shared.model.TriggerEntity;
88
import org.sterl.spring.persistent_tasks.trigger.component.StateSerializer;
99

10+
import lombok.extern.slf4j.Slf4j;
11+
12+
@Slf4j
1013
public enum ToTrigger implements ExtendetConvert<HasTrigger, Trigger> {
1114
INSTANCE;
1215

@@ -29,8 +32,25 @@ public Trigger convert(@NonNull HasTrigger hasData) {
2932
result.setRunAt(source.getRunAt());
3033
result.setRunningDurationInMs(source.getRunningDurationInMs());
3134
result.setStart(source.getStart());
32-
result.setState(SERIALIZER.deserialize(source.getState()));
35+
try {
36+
result.setState(SERIALIZER.deserialize(source.getState()));
37+
} catch (Exception e) {
38+
var info = """
39+
Failed to deserialize state
40+
This is most likely due to an incompatible code change.
41+
Old states in the DB cannot be read anymore/deserialized and cast to the given class.
42+
""";
43+
result.setState(new FailedToReadStateInfo(e.getMessage(), info));
44+
log.warn("""
45+
Failed to deserialize state of {}.
46+
This is most likely due to an incompatible code change.
47+
Old states in the DB cannot be read anymore/deserialized and cast to the given class.
48+
{}""",
49+
source.getKey(), e.getMessage());
50+
}
3351
result.setStatus(source.getStatus());
3452
return result;
3553
}
54+
55+
record FailedToReadStateInfo(String message, String info) {}
3656
}

core/src/main/java/org/sterl/spring/persistent_tasks/trigger/component/ReadTriggerComponent.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ public Page<RunningTriggerEntity> searchTriggers(@Nullable TriggerSearch search,
7777
return result;
7878
} else {
7979
log.debug("Empty search={}, selecting all triggers for page={}", search, page);
80-
return triggerRepository.findAll(page);
80+
var result = triggerRepository.findAll(page);
81+
return result;
8182
}
82-
8383
}
8484

8585
public Page<TriggerGroup> searchGroupedTriggers(@Nullable TriggerSearch search, Pageable page) {

core/src/main/java/org/sterl/spring/persistent_tasks/trigger/component/StateSerializer.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
import java.io.ByteArrayInputStream;
44
import java.io.ByteArrayOutputStream;
5-
import java.io.ObjectInput;
5+
import java.io.IOException;
6+
import java.io.InputStream;
67
import java.io.ObjectInputStream;
78
import java.io.ObjectOutputStream;
9+
import java.io.ObjectStreamClass;
810
import java.io.Serializable;
911

1012
import org.sterl.spring.persistent_tasks.exception.SpringPersistentTaskException;
@@ -50,7 +52,7 @@ public Serializable deserialize(byte[] bytes) {
5052
}
5153

5254
var bis = new ByteArrayInputStream(bytes);
53-
try (ObjectInput in = new ObjectInputStream(bis)) {
55+
try (var in = new ContextClassLoaderObjectInputStream(bis)) {
5456
return (Serializable)in.readObject();
5557
} catch (Exception ex) {
5658
throw new DeSerializationFailedException(bytes, ex);
@@ -65,4 +67,18 @@ public Serializable deserializeOrNull(byte[] bytes) {
6567
return null;
6668
}
6769
}
70+
71+
// needed for spring boot developer tools
72+
// https://github.com/sterlp/spring-persistent-tasks/issues/19
73+
static class ContextClassLoaderObjectInputStream extends ObjectInputStream {
74+
ContextClassLoaderObjectInputStream(InputStream in) throws IOException {
75+
super(in);
76+
}
77+
@Override
78+
protected Class<?> resolveClass(ObjectStreamClass desc)
79+
throws IOException, ClassNotFoundException {
80+
return Class.forName(desc.getName(), false,
81+
Thread.currentThread().getContextClassLoader());
82+
}
83+
}
6884
}

core/src/test/java/org/sterl/spring/persistent_tasks/trigger/api/TriggerResourceTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import com.fasterxml.jackson.core.JsonProcessingException;
2929
import com.fasterxml.jackson.databind.JsonMappingException;
30+
import com.github.f4b6a3.uuid.UuidCreator;
3031

3132
class TriggerResourceTest extends AbstractSpringTest {
3233

@@ -217,6 +218,27 @@ void testGroupSearch() throws JsonMappingException, JsonProcessingException {
217218
assertThat(result.getBody()).contains("\"groupByValue\":\"a1\"");
218219
}
219220

221+
@Test
222+
void testReadIncompatibleTriggerState() {
223+
// GIVEN we have a bad state we cannot read in the DB
224+
var key = UuidCreator.getTimeOrdered().toString();
225+
trx.execute(t -> {
226+
return triggerRepository.save(new RunningTriggerEntity(
227+
new TriggerKey(key, "slowTask")
228+
).withState(new byte[] {12, 54, 33})
229+
);
230+
});
231+
232+
// WHEN
233+
assertThat(triggerRepository.count()).isGreaterThanOrEqualTo(1L);
234+
var response = template.getForEntity(baseUrl, String.class);
235+
236+
// THEN
237+
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
238+
assertThat(response.getBody()).contains(key);
239+
assertThat(response.getBody()).contains("Failed to deserialize state of length");
240+
}
241+
220242
private RunningTriggerEntity createStatus(TriggerKey key, TriggerStatus status) {
221243
final var now = OffsetDateTime.now();
222244
final var isCancel = status == TriggerStatus.CANCELED;

example/pom.xml

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<!--
1818
<spt.version>2.1.2</spt.version>
1919
-->
20-
<spt.version>2.2.3-SNAPSHOT</spt.version>
20+
<spt.version>2.2.4-SNAPSHOT</spt.version>
2121
</properties>
2222

2323
<dependencies>
@@ -48,12 +48,6 @@
4848
<groupId>org.springframework.boot</groupId>
4949
<artifactId>spring-boot-starter-web</artifactId>
5050
</dependency>
51-
52-
<dependency>
53-
<groupId>org.springframework.data</groupId>
54-
<artifactId>spring-data-envers</artifactId>
55-
</dependency>
56-
5751

5852
<dependency>
5953
<groupId>org.springframework.boot</groupId>
@@ -69,7 +63,7 @@
6963
<dependency>
7064
<groupId>org.springdoc</groupId>
7165
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
72-
<version>2.6.0</version>
66+
<version>2.8.13</version>
7367
</dependency>
7468

7569
<dependency>
@@ -98,5 +92,24 @@
9892
<artifactId>spring-boot-starter-test</artifactId>
9993
<scope>test</scope>
10094
</dependency>
95+
<dependency>
96+
<groupId>org.springframework.boot</groupId>
97+
<artifactId>spring-boot-starter</artifactId>
98+
</dependency>
99+
<dependency>
100+
<groupId>org.springframework.boot</groupId>
101+
<artifactId>spring-boot-devtools</artifactId>
102+
<scope>runtime</scope>
103+
<optional>true</optional>
104+
</dependency>
101105
</dependencies>
106+
107+
<build>
108+
<plugins>
109+
<plugin>
110+
<groupId>org.springframework.boot</groupId>
111+
<artifactId>spring-boot-maven-plugin</artifactId>
112+
</plugin>
113+
</plugins>
114+
</build>
102115
</project>

0 commit comments

Comments
 (0)