[java-shib-attribute] branch main updated: JSATTR-14 - Registry loader constructor breaks on jar-based classpaths
Codeberg
noreply at shibboleth.net
Thu Jul 16 14:23:17 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository java-shib-attribute.
View the commit online:
https://codeberg.org/Shibboleth/java-shib-attribute/commit/4fd36f9e21ae01595c314c5c5a2913d393120c21
The following commit(s) were added to refs/heads/main by this push:
new 4fd36f9e2 JSATTR-14 - Registry loader constructor breaks on jar-based classpaths
4fd36f9e2 is described below
commit 4fd36f9e21ae01595c314c5c5a2913d393120c21
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Thu Jul 16 10:23:01 2026 -0400
JSATTR-14 - Registry loader constructor breaks on jar-based classpaths
https://shibboleth.atlassian.net/browse/JSATTR-14
Add new constructors and fail fast flag to control behavior better.
---
.../transcoding/impl/TranscodingRuleLoader.java | 197 +++++++++++++++++----
1 file changed, 161 insertions(+), 36 deletions(-)
diff --git a/shib-attribute-impl/src/main/java/net/shibboleth/idp/attribute/transcoding/impl/TranscodingRuleLoader.java b/shib-attribute-impl/src/main/java/net/shibboleth/idp/attribute/transcoding/impl/TranscodingRuleLoader.java
index f9c423fc3..323c9a7f0 100644
--- a/shib-attribute-impl/src/main/java/net/shibboleth/idp/attribute/transcoding/impl/TranscodingRuleLoader.java
+++ b/shib-attribute-impl/src/main/java/net/shibboleth/idp/attribute/transcoding/impl/TranscodingRuleLoader.java
@@ -18,6 +18,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
+import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
@@ -29,6 +30,7 @@ import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
import net.shibboleth.idp.attribute.transcoding.TranscodingRule;
import net.shibboleth.shared.annotation.ParameterName;
@@ -51,9 +53,12 @@ public class TranscodingRuleLoader {
/** Rules loaded. */
@Nonnull private final Collection<TranscodingRule> rules;
+
+ /** Whether to rethrow exceptions during construction or populate empty. */
+ private final boolean failOnErrors;
/**
- * Load rules from all files found below a directory root.
+ * Load rules from all files found below a directory root expressed as a Spring resource.
*
* <p>Files are assumed to be Java property files in text format.</p>
*
@@ -62,49 +67,65 @@ public class TranscodingRuleLoader {
* <p>The file extensions must include the period, and only apply to
* files, while all directories will be examined.</p>
*
- * @param dir root to search
+ * @param resource root to search
* @param extensions file extensions to include
+ * @param failFast true iff I/O failures should be surfaced
*
* @throws IOException if an error occurs
+ *
+ * @since 5.3.0
*/
- public TranscodingRuleLoader(@Nonnull @ParameterName(name="dir") final Path dir,
- @Nullable @ParameterName(name="extensions") final Collection<String> extensions)
- throws IOException {
- log.debug("Loading rules from directory ({})", dir);
- final Collection<TranscodingRule> holder = new ArrayList<>();
+ public TranscodingRuleLoader(@Nonnull @ParameterName(name="resource") final Resource resource,
+ @Nullable @ParameterName(name="extensions") final Collection<String> extensions,
+ @ParameterName(name="failFast") final boolean failFast) throws IOException {
- try (final DirectoryStream<Path> dirstream = Files.newDirectoryStream(dir)) {
- for (final Path child : dirstream) {
- final File file = child.toFile();
- if (file.isDirectory()) {
- try {
- holder.addAll(new TranscodingRuleLoader(child, extensions).getRules());
- } catch (final IOException e) {
- log.error("Failed to load rules from directory ({})", file, e);
- }
- } else if (extensions == null || extensions.isEmpty() ||
- PredicateSupport.anyMatch((String ext) -> file.getName().endsWith(ext)).test(extensions)) {
- log.debug("Loading rule from property set in file ({})", file);
- try {
- final TranscodingRule rule =
- TranscodingRule.fromResource(ResourceHelper.of(new FileSystemResource(file)));
- if (rule.getMap().isEmpty()) {
- log.info("Transcoding file {} contained no rules", child);
- } else {
- holder.add(rule);
- }
- } catch (final IOException e) {
- log.error("Failed to load rule from file ({})", file, e);
- }
- } else {
- log.debug("Ignoring file ({}) with non-matching extension", file);
- }
+ failOnErrors = failFast;
+
+ final Path path;
+ try {
+ path = resource.getFilePath();
+ } catch (final Exception e) {
+ log.error("Exception accessing resource ({}) as directory", resource, e);
+ if (failOnErrors) {
+ throw e;
}
+ rules = CollectionSupport.emptyList();
+ return;
}
-
- rules = CollectionSupport.copyToList(holder);
+ rules = load(path, extensions);
}
+ /**
+ * Equivalent to {@link #TranscodingRuleLoader(Resource, Collection, boolean)}
+ * with true fail fast behavior.
+ *
+ * @param resource root to search
+ * @param extensions file extensions to include
+ *
+ * @throws IOException if an error occurs
+ *
+ * @since 5.3.0
+ */
+ public TranscodingRuleLoader(@Nonnull @ParameterName(name="resource") final Resource resource,
+ @Nullable @ParameterName(name="extensions") final Collection<String> extensions) throws IOException {
+ this(resource, extensions, true);
+ }
+
+ /**
+ * Equivalent to {@link #TranscodingRuleLoader(Resource, Collection, boolean)}
+ * with null extensions and true fail fast behavior.
+ *
+ * @param resource root to search
+ *
+ * @throws IOException if an error occurs
+ *
+ * @since 5.3.0
+ */
+ public TranscodingRuleLoader(@Nonnull @ParameterName(name="resource") final Resource resource)
+ throws IOException {
+ this(resource, null, true);
+ }
+
/**
* Load rules from all files found below a directory root.
*
@@ -112,12 +133,50 @@ public class TranscodingRuleLoader {
*
* <p>Individual rules that fail to load will be skipped.</p>
*
+ * <p>The file extensions must include the period, and only apply to
+ * files, while all directories will be examined.</p>
+ *
+ * @param dir root to search
+ * @param extensions file extensions to include
+ * @param failFast true iff I/O failures should be surfaced
+ *
+ * @throws IOException if an error occurs
+ *
+ * @since 5.3.0
+ */
+ public TranscodingRuleLoader(@Nonnull @ParameterName(name="dir") final Path dir,
+ @Nullable @ParameterName(name="extensions") final Collection<String> extensions,
+ @ParameterName(name="failFast") final boolean failFast)
+ throws IOException {
+
+ failOnErrors = failFast;
+ rules = load(dir, extensions);
+ }
+
+ /**
+ * Equivalent to {@link #TranscodingRuleLoader(Path, Collection, boolean)}
+ * with null extensions and true fail fast behavior.
+ *
+ * @param dir root to search
+ * @param extensions file extensions to include
+ *
+ * @throws IOException if an error occurs
+ */
+ public TranscodingRuleLoader(@Nonnull @ParameterName(name="dir") final Path dir,
+ @Nullable @ParameterName(name="extensions") final Collection<String> extensions) throws IOException {
+ this(dir, extensions, true);
+ }
+
+ /**
+ * Equivalent to {@link #TranscodingRuleLoader(Path, Collection, boolean)}
+ * with null extensions and true fail fast behavior.
+ *
* @param dir root to search
*
* @throws IOException if an error occurs
*/
public TranscodingRuleLoader(@Nonnull @ParameterName(name="dir") final Path dir) throws IOException {
- this(dir, null);
+ this(dir, null, true);
}
/**
@@ -128,6 +187,9 @@ public class TranscodingRuleLoader {
public TranscodingRuleLoader(@Nonnull @ParameterName(name="maps") final Collection<Map<String,Object>> maps) {
Constraint.isNotNull(maps, "Input collection cannot be null");
+ // Irrelevant.
+ failOnErrors = true;
+
rules = maps
.stream()
.map(m -> {
@@ -137,6 +199,69 @@ public class TranscodingRuleLoader {
.collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList()))
.get();
}
+
+// Checkstyle: CyclomaticComplexity OFF
+ /**
+ * Performs the load step using the supplied parameters from the various constructors.
+ *
+ * @param dir path to attempt load from
+ * @param extensions file extensions to include
+ *
+ * @return the loaded rules
+ *
+ * @throws IOException on failure
+ *
+ * @since 5.3.0
+ */
+ @Nonnull @Unmodifiable @NotLive private Collection<TranscodingRule> load(
+ @Nonnull @ParameterName(name="dir") final Path dir,
+ @Nullable @ParameterName(name="extensions") final Collection<String> extensions) throws IOException {
+
+ log.debug("Loading rules from directory ({})", dir);
+ final Collection<TranscodingRule> holder = new ArrayList<>();
+
+ try (final DirectoryStream<Path> dirstream = Files.newDirectoryStream(dir)) {
+ for (final Path child : dirstream) {
+ final File file = child.toFile();
+ if (file.isDirectory()) {
+ try {
+ holder.addAll(new TranscodingRuleLoader(child, extensions, failOnErrors).getRules());
+ } catch (final IOException e) {
+ log.error("Failed to load rules from directory ({})", file, e);
+ }
+ } else if (extensions == null || extensions.isEmpty() ||
+ PredicateSupport.anyMatch((String ext) -> file.getName().endsWith(ext)).test(extensions)) {
+ log.debug("Loading rule from property set in file ({})", file);
+ try {
+ final TranscodingRule rule =
+ TranscodingRule.fromResource(ResourceHelper.of(new FileSystemResource(file)));
+ if (rule.getMap().isEmpty()) {
+ log.info("Transcoding file {} contained no rules", child);
+ } else {
+ holder.add(rule);
+ }
+ } catch (final IOException e) {
+ log.error("Failed to load rule from file ({})", file, e);
+ }
+ } else {
+ log.debug("Ignoring file ({}) with non-matching extension", file);
+ }
+ }
+ } catch (final NotDirectoryException e) {
+ log.error("TranscodingRuleLoader path {{}} was not a directory", dir, e);
+ if (failOnErrors) {
+ throw e;
+ }
+ } catch (final IOException e) {
+ log.error("Exception accessing path {{}}", dir, e);
+ if (failOnErrors) {
+ throw e;
+ }
+ }
+
+ return CollectionSupport.copyToList(holder);
+ }
+// Checkstyle: CyclomaticComplexity ON
/**
* Get the rules loaded by this object.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list