mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-02 21:03:34 +03:00
Skip unreadable policy source/policy rows instead of crashing :) (#7034)
# Description of Changes Thanks james for the prod issue :) --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details.
This commit is contained in:
+23
-5
@@ -8,6 +8,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProp
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
@@ -15,6 +16,7 @@ import tools.jackson.databind.ObjectMapper;
|
||||
* Durable {@link SourceStore} backed by JPA; the runtime store. Sources are persisted as JSON via
|
||||
* {@link SourceEntity}, with scalar columns kept in sync for querying.
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnBooleanProperty(name = "policies.enabled")
|
||||
@@ -53,17 +55,20 @@ public class JpaSourceStore implements SourceStore {
|
||||
|
||||
@Override
|
||||
public Optional<Source> get(String id) {
|
||||
return repository.findById(id).map(this::toSource);
|
||||
return repository.findById(id).flatMap(this::toSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Source> all() {
|
||||
return repository.findAll().stream().map(this::toSource).toList();
|
||||
return repository.findAll().stream().map(this::toSource).flatMap(Optional::stream).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Source> findByTeam(Long teamId) {
|
||||
return repository.findByTeam(teamId).stream().map(this::toSource).toList();
|
||||
return repository.findByTeam(teamId).stream()
|
||||
.map(this::toSource)
|
||||
.flatMap(Optional::stream)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,7 +80,20 @@ public class JpaSourceStore implements SourceStore {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Source toSource(SourceEntity entity) {
|
||||
return objectMapper.readValue(entity.getSourceJson(), Source.class);
|
||||
// Skip (don't fail) rows whose JSON can't be read - e.g. written by another app version/key.
|
||||
// One unreadable row must never abort a bulk read or crash startup.
|
||||
private Optional<Source> toSource(SourceEntity entity) {
|
||||
try {
|
||||
return Optional.of(objectMapper.readValue(entity.getSourceJson(), Source.class));
|
||||
} catch (Exception e) {
|
||||
log.error(
|
||||
"Skipping unreadable policy source id={} name={}: stored JSON could not be"
|
||||
+ " parsed ({}). Likely written by a different app version or"
|
||||
+ " encryption key.",
|
||||
entity.getId(),
|
||||
entity.getName(),
|
||||
e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-5
@@ -10,6 +10,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import stirling.software.proprietary.policy.model.Policy;
|
||||
|
||||
@@ -19,6 +20,7 @@ import tools.jackson.databind.ObjectMapper;
|
||||
* Durable {@link PolicyStore} backed by JPA; the runtime store. Policies are persisted as JSON via
|
||||
* {@link PolicyEntity}, with scalar columns kept in sync for querying.
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnBooleanProperty(name = "policies.enabled")
|
||||
@@ -98,23 +100,30 @@ public class JpaPolicyStore implements PolicyStore {
|
||||
|
||||
@Override
|
||||
public Optional<Policy> get(String id) {
|
||||
return repository.findById(id).map(this::toPolicy);
|
||||
return repository.findById(id).flatMap(this::toPolicy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> all() {
|
||||
return repository.findAllOrdered().stream().map(this::toPolicy).toList();
|
||||
return repository.findAllOrdered().stream()
|
||||
.map(this::toPolicy)
|
||||
.flatMap(Optional::stream)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByTeam(Long teamId) {
|
||||
return repository.findByTeam(teamId).stream().map(this::toPolicy).toList();
|
||||
return repository.findByTeam(teamId).stream()
|
||||
.map(this::toPolicy)
|
||||
.flatMap(Optional::stream)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByTriggerType(String triggerType) {
|
||||
return repository.findByTriggerTypeAndEnabledTrue(triggerType).stream()
|
||||
.map(this::toPolicy)
|
||||
.flatMap(Optional::stream)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@@ -127,7 +136,19 @@ public class JpaPolicyStore implements PolicyStore {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Policy toPolicy(PolicyEntity entity) {
|
||||
return objectMapper.readValue(entity.getPolicyJson(), Policy.class);
|
||||
// Skip (don't fail) rows whose JSON can't be read - e.g. written by another app version/key.
|
||||
// One unreadable row must never abort a bulk read or crash startup.
|
||||
private Optional<Policy> toPolicy(PolicyEntity entity) {
|
||||
try {
|
||||
return Optional.of(objectMapper.readValue(entity.getPolicyJson(), Policy.class));
|
||||
} catch (Exception e) {
|
||||
log.error(
|
||||
"Skipping unreadable policy id={} name={}: stored JSON could not be parsed"
|
||||
+ " ({}). Likely written by a different app version or encryption key.",
|
||||
entity.getId(),
|
||||
entity.getName(),
|
||||
e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user