[java-opensaml] branch main updated: IDP-2083 - Treat NonnullElements as the default for collections

Scott Cantor cantor.2 at osu.edu
Thu May 4 15:52:18 UTC 2023


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch main
in repository java-opensaml.

View the commit online:
http://git.shibboleth.net/view/?p=java-opensaml.git;a=commit;h=be3d3f98de892848e005fe82e999670fd33ea895

The following commit(s) were added to refs/heads/main by this push:
     new be3d3f98d IDP-2083 - Treat NonnullElements as the default for collections
be3d3f98d is described below

commit be3d3f98de892848e005fe82e999670fd33ea895
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu May 4 11:52:15 2023 -0400

    IDP-2083 - Treat NonnullElements as the default for collections
    
    https://shibboleth.atlassian.net/browse/IDP-2083
    
    Review opensaml-core-api.
    Fix various warnings and add more missing annotations.
---
 .../org/opensaml/core/config/Configuration.java    | 10 ++-
 .../opensaml/core/config/ConfigurationService.java |  9 +-
 .../core/config/InitializationService.java         |  1 +
 .../java/org/opensaml/core/config/Initializer.java |  4 +-
 .../org/opensaml/core/config/package-info.java     |  5 +-
 ...actFilesystemConfigurationPropertiesSource.java |  6 +-
 .../config/provider/MapBasedConfiguration.java     | 12 +--
 ...ystemPropertyConfigurationPropertiesSource.java |  2 +-
 .../ThreadLocalConfigurationPropertiesHolder.java  |  8 +-
 .../ThreadLocalConfigurationPropertiesSource.java  |  2 +-
 .../core/config/provider/package-info.java         |  5 +-
 .../core/criterion/SatisfyAnyCriterion.java        |  8 +-
 .../org/opensaml/core/criterion/package-info.java  |  5 +-
 .../core/metrics/LoggerDrivenMetricFilter.java     |  5 +-
 .../org/opensaml/core/metrics/package-info.java    |  4 +-
 .../main/java/org/opensaml/core/package-info.java  |  5 +-
 .../xml/AbstractElementExtensibleXMLObject.java    |  7 +-
 ...stractElementExtensibleXMLObjectMarshaller.java |  6 +-
 ...ractElementExtensibleXMLObjectUnmarshaller.java |  6 +-
 .../core/xml/AbstractExtensibleXMLObject.java      |  1 +
 .../xml/AbstractExtensibleXMLObjectMarshaller.java |  5 --
 .../AbstractExtensibleXMLObjectUnmarshaller.java   |  8 +-
 .../org/opensaml/core/xml/AbstractXMLObject.java   |  4 +-
 .../core/xml/AbstractXMLObjectBuilder.java         | 22 +++--
 .../core/xml/AttributeExtensibleXMLObject.java     |  3 +-
 .../java/org/opensaml/core/xml/BaseBearing.java    | 10 +--
 .../core/xml/ElementExtensibleXMLObject.java       |  5 +-
 .../main/java/org/opensaml/core/xml/IdBearing.java | 10 +--
 .../java/org/opensaml/core/xml/LangBearing.java    | 10 +--
 .../main/java/org/opensaml/core/xml/Namespace.java | 26 ++++--
 .../org/opensaml/core/xml/NamespaceManager.java    | 33 ++++----
 .../java/org/opensaml/core/xml/SpaceBearing.java   | 12 +--
 .../org/opensaml/core/xml/XMLObjectBuilder.java    | 11 +--
 .../config/XMLObjectProviderRegistrySupport.java   |  4 +-
 .../org/opensaml/core/xml/config/package-info.java |  5 +-
 .../core/xml/io/AbstractXMLObjectMarshaller.java   |  4 +-
 .../opensaml/core/xml/io/MarshallerFactory.java    |  5 +-
 .../opensaml/core/xml/io/UnmarshallerFactory.java  |  4 +-
 .../org/opensaml/core/xml/io/package-info.java     |  5 +-
 .../java/org/opensaml/core/xml/package-info.java   |  5 +-
 ...actConditionalLoadXMLObjectLoadSaveManager.java |  4 +-
 .../xml/persist/FilesystemLoadSaveManager.java     | 54 +++++++-----
 .../core/xml/persist/MapLoadSaveManager.java       | 30 ++++---
 .../core/xml/persist/XMLObjectLoadSaveManager.java |  5 +-
 .../opensaml/core/xml/persist/package-info.java    |  5 +-
 .../org/opensaml/core/xml/schema/package-info.java |  5 +-
 .../org/opensaml/core/xml/util/AttributeMap.java   |  5 +-
 .../java/org/opensaml/core/xml/util/IDIndex.java   |  7 +-
 .../core/xml/util/XMLAttributeSupport.java         | 97 ++++++++++------------
 .../opensaml/core/xml/util/XMLObjectSource.java    |  3 +-
 .../opensaml/core/xml/util/XMLObjectSupport.java   | 22 ++---
 .../org/opensaml/core/xml/util/package-info.java   |  5 +-
 .../core/xml/tests/XMLObjectXSIAttribsTest.java    |  7 +-
 .../impl/LocalDynamicMetadataResolverTest.java     | 24 ++++--
 54 files changed, 325 insertions(+), 250 deletions(-)

diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/Configuration.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/Configuration.java
index 162c47651..6138a6620 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/Configuration.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/Configuration.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.core.config;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 /**
@@ -40,7 +41,7 @@ public interface Configuration {
      * 
      * @return the instance of the registered configuration interface, or null
      */
-    @Nullable public <T extends Object> T get(Class<T> configClass, String partitionName);
+    @Nullable <T extends Object> T get(@Nonnull final Class<T> configClass, @Nonnull final String partitionName);
     
     /**
      * Register a configuration instance.
@@ -52,7 +53,8 @@ public interface Configuration {
      * @param configInstance the configuration implementation instance being registered
      * @param partitionName the partition name to use
      */
-    public <T extends Object, I extends T> void register(Class<T> configClass, I configInstance, String partitionName);
+    <T extends Object, I extends T> void register(@Nonnull final Class<T> configClass,
+            @Nonnull final I configInstance, @Nonnull final String partitionName);
     
     /**
      * Deregister a configuration instance.
@@ -64,6 +66,6 @@ public interface Configuration {
      * 
      * @return the configuration implementation instance which was deregistered, or null
      */
-    @Nullable public <T extends Object> T deregister(Class<T> configClass, String partitionName);
+    @Nullable <T extends Object> T deregister(@Nonnull final Class<T> configClass, @Nonnull final String partitionName);
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/ConfigurationService.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/ConfigurationService.java
index cdd2ad7fc..cb2b612a7 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/ConfigurationService.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/ConfigurationService.java
@@ -24,6 +24,7 @@ import java.util.ServiceLoader;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import net.shibboleth.shared.annotation.constraint.Live;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -68,7 +69,8 @@ public class ConfigurationService {
     @Nonnull private static final Logger LOG = LoggerFactory.getLogger(ConfigurationService.class);
     
     /** The service loader used to locate registered implementations of ConfigurationPropertiesSource. */
-    private static ServiceLoader<ConfigurationPropertiesSource> configPropertiesLoader = 
+    @SuppressWarnings("null")
+    @Nonnull private static ServiceLoader<ConfigurationPropertiesSource> configPropertiesLoader = 
         ServiceLoader.load(ConfigurationPropertiesSource.class) ;
     
     /** The configuration instance to use. */
@@ -149,8 +151,7 @@ public class ConfigurationService {
      * <p>
      * The properties set is obtained from the first registered instance of 
      * {@link ConfigurationPropertiesSource} which returns a non-null properties set.
-     * The implementations of properties sources to use
-     * are obtained via the Java Services API.
+     * The implementations of properties sources to use are obtained via the Java Services API.
      * </p>
      * 
      * <p>
@@ -160,7 +161,7 @@ public class ConfigurationService {
      * 
      * @return the set of configuration meta-properties
      */
-    @Nullable public static Properties getConfigurationProperties() {
+    @Nullable @Live public static Properties getConfigurationProperties() {
         //TODO make these immutable?
         LOG.trace("Resolving configuration propreties source");
         final Iterator<ConfigurationPropertiesSource> iter = configPropertiesLoader.iterator();
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/InitializationService.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/InitializationService.java
index 5f254896b..a51a53c60 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/InitializationService.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/InitializationService.java
@@ -68,6 +68,7 @@ public class InitializationService {
      * 
      * @return the service loader instance to use
      */
+    @SuppressWarnings("null")
     @Nonnull private static ServiceLoader<Initializer> getServiceLoader() {
         // TODO ideally would store off loader and reuse on subsequent calls,
         // so inited state in providers would be persisted across calls,
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/Initializer.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/Initializer.java
index b07057f03..7a477cfb6 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/Initializer.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/Initializer.java
@@ -32,6 +32,6 @@ public interface Initializer {
      * 
      * @throws InitializationException if initialization could not be completed successfully
      */
-    public void init() throws InitializationException;
+    void init() throws InitializationException;
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/package-info.java
index b888c9d92..69ff73637 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Interfaces and classes related to library configuration and initialization. */
-package org.opensaml.core.config;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core.config;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/AbstractFilesystemConfigurationPropertiesSource.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/AbstractFilesystemConfigurationPropertiesSource.java
index 7196ab8f8..98af8abe6 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/AbstractFilesystemConfigurationPropertiesSource.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/AbstractFilesystemConfigurationPropertiesSource.java
@@ -43,12 +43,13 @@ import net.shibboleth.shared.primitive.StringSupport;
  * </p>
  */
 public abstract class AbstractFilesystemConfigurationPropertiesSource implements ConfigurationPropertiesSource {
-    /** Cache of properties. */
-    private Properties cachedProperties;
     
     /** Logger. */
     @Nonnull private Logger log = LoggerFactory.getLogger(AbstractFilesystemConfigurationPropertiesSource.class);
     
+    /** Cache of properties. */
+    @Nullable private Properties cachedProperties;
+
     /** {@inheritDoc} */
     @Nullable public Properties getProperties() {
         final String fileName = StringSupport.trimOrNull(getFilename());
@@ -86,4 +87,5 @@ public abstract class AbstractFilesystemConfigurationPropertiesSource implements
      * @return the absolute filename
      */
     @Nullable protected abstract String getFilename();
+    
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/MapBasedConfiguration.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/MapBasedConfiguration.java
index 6c26847f8..4d153f889 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/MapBasedConfiguration.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/MapBasedConfiguration.java
@@ -49,7 +49,8 @@ public class MapBasedConfiguration implements Configuration {
      * 
      * @return the instance of the registered configuration interface, or null
      */
-    @Nullable public <T extends Object> T get(final Class<T> configClass, final String partitionName) {
+    @Nullable public <T extends Object> T get(@Nonnull final Class<T> configClass,
+            @Nonnull final String partitionName) {
         final Map<String, Object> partition = getPartition(partitionName);
         return configClass.cast(partition.get(configClass.getName()));
     }
@@ -64,8 +65,8 @@ public class MapBasedConfiguration implements Configuration {
      * @param configuration the configuration implementation instance being registered
      * @param partitionName the partition name to use
      */
-    public <T extends Object, I extends T> void register(final Class<T> configClass, final I configuration,
-            final String partitionName) {
+    public <T extends Object, I extends T> void register(@Nonnull final Class<T> configClass,
+            @Nonnull final I configuration, @Nonnull final String partitionName) {
         final Map<String, Object> partition = getPartition(partitionName);
         partition.put(configClass.getName(), configuration);
     }
@@ -80,7 +81,8 @@ public class MapBasedConfiguration implements Configuration {
      * 
      * @return the configuration implementation instance which was deregistered, or null
      */
-    @Nullable public <T extends Object> T deregister(final Class<T> configClass, final String partitionName) {
+    @Nullable public <T extends Object> T deregister(@Nonnull final Class<T> configClass,
+            @Nonnull final String partitionName) {
         final Map<String, Object> partition = getPartition(partitionName);
         synchronized (partition) {
             final T old = configClass.cast(partition.get(configClass.getName()));
@@ -96,7 +98,7 @@ public class MapBasedConfiguration implements Configuration {
      * 
      * @return the Map corresponding to the partition name.  A new empty Map will be created if necessary
      */
-    @Nonnull private synchronized Map<String, Object> getPartition(final String partitionName) {
+    @Nonnull private synchronized Map<String, Object> getPartition(@Nonnull final String partitionName) {
         Map<String, Object> partition = storage.get(partitionName);
         if (partition == null) {
             partition = new ConcurrentHashMap<>();
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/SystemPropertyConfigurationPropertiesSource.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/SystemPropertyConfigurationPropertiesSource.java
index be4afbcc7..2482f3703 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/SystemPropertyConfigurationPropertiesSource.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/SystemPropertyConfigurationPropertiesSource.java
@@ -33,4 +33,4 @@ public class SystemPropertyConfigurationPropertiesSource implements Configuratio
         return System.getProperties();
     }
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/ThreadLocalConfigurationPropertiesHolder.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/ThreadLocalConfigurationPropertiesHolder.java
index 147a2c63a..aa92d7e3c 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/ThreadLocalConfigurationPropertiesHolder.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/ThreadLocalConfigurationPropertiesHolder.java
@@ -28,7 +28,7 @@ import javax.annotation.Nullable;
 public final class ThreadLocalConfigurationPropertiesHolder {
     
     /** ThreadLocal storage for the properties set. */
-    @Nonnull private static ThreadLocal<Properties> properties = new ThreadLocal<>();
+    @Nonnull private static final ThreadLocal<Properties> PROPERTIES = new ThreadLocal<>();
     
     /** Constructor. */
     private ThreadLocalConfigurationPropertiesHolder() {}
@@ -39,7 +39,7 @@ public final class ThreadLocalConfigurationPropertiesHolder {
      * @return the thread-local Properties
      */
     @Nullable public static Properties getProperties() {
-        return properties.get();
+        return PROPERTIES.get();
     }
     
     /**
@@ -48,14 +48,14 @@ public final class ThreadLocalConfigurationPropertiesHolder {
      * @param newProperties the new thread-local Properties instance
      */
     public static void setProperties(@Nullable final Properties newProperties) {
-        properties.set(newProperties);
+        PROPERTIES.set(newProperties);
     }
     
     /**
      *  Clear the thread-local configuration Properties instance.
      */
     public static void clear() {
-        properties.remove();
+        PROPERTIES.remove();
     }
 
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/ThreadLocalConfigurationPropertiesSource.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/ThreadLocalConfigurationPropertiesSource.java
index 5955c6a9f..6d6f5ac7c 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/ThreadLocalConfigurationPropertiesSource.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/ThreadLocalConfigurationPropertiesSource.java
@@ -54,4 +54,4 @@ public class ThreadLocalConfigurationPropertiesSource implements ConfigurationPr
         return ThreadLocalConfigurationPropertiesHolder.getProperties();
     }
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/package-info.java
index 35030bf32..24dd68227 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/config/provider/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Implementation of library configuration and initialization. */
-package org.opensaml.core.config.provider;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core.config.provider;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/criterion/SatisfyAnyCriterion.java b/opensaml-core-api/src/main/java/org/opensaml/core/criterion/SatisfyAnyCriterion.java
index f80aec50f..a45e27bfd 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/criterion/SatisfyAnyCriterion.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/criterion/SatisfyAnyCriterion.java
@@ -30,13 +30,13 @@ import net.shibboleth.shared.resolver.Criterion;
 public class SatisfyAnyCriterion implements Criterion {
     
     /** The satisfyAny criterion value. */
-    private Boolean satisfyAny;
+    private boolean satisfyAny;
     
     /**
      * Constructor.
      */
     public SatisfyAnyCriterion() {
-        satisfyAny = Boolean.TRUE;
+        satisfyAny = true;
     }
     
     /**
@@ -59,7 +59,7 @@ public class SatisfyAnyCriterion implements Criterion {
 
     /** {@inheritDoc} */
     public int hashCode() {
-        return satisfyAny.hashCode();
+        return Boolean.valueOf(satisfyAny).hashCode();
     }
 
     /** {@inheritDoc} */
@@ -81,4 +81,4 @@ public class SatisfyAnyCriterion implements Criterion {
                 .addValue(satisfyAny).toString();
     }
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/criterion/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/criterion/package-info.java
index 2e0a8f50a..56684360a 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/criterion/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/criterion/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Core {@link net.shibboleth.shared.resolver.Criterion} subclasses. */
-package org.opensaml.core.criterion;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core.criterion;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/metrics/LoggerDrivenMetricFilter.java b/opensaml-core-api/src/main/java/org/opensaml/core/metrics/LoggerDrivenMetricFilter.java
index 906c3ae64..70b24dd50 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/metrics/LoggerDrivenMetricFilter.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/metrics/LoggerDrivenMetricFilter.java
@@ -24,7 +24,6 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.shared.annotation.ParameterName;
-import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.Constraint;
@@ -67,7 +66,7 @@ public class LoggerDrivenMetricFilter implements MetricFilter {
     @Nonnull @NotEmpty private final String loggerPrefix;
     
     /** Map of metrics to logging levels. */
-    @Nonnull @NonnullElements private final Map<String,Level> levelMap;
+    @Nonnull private final Map<String,Level> levelMap;
     
     /**
      * Constructor.
@@ -85,7 +84,7 @@ public class LoggerDrivenMetricFilter implements MetricFilter {
      * @param map map of metric names to logging levels
      */
     public LoggerDrivenMetricFilter(@Nonnull @NotEmpty @ParameterName(name="prefix") final String prefix,
-            @Nullable @NonnullElements @ParameterName(name="map") final Map<String,Level> map) {
+            @Nullable @ParameterName(name="map") final Map<String,Level> map) {
         loggerPrefix = Constraint.isNotNull(StringSupport.trimOrNull(prefix), "Prefix cannot be null or empty.");
         
         if (map == null || map.isEmpty()) {
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/metrics/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/metrics/package-info.java
index efd3c3c54..b1d020a67 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/metrics/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/metrics/package-info.java
@@ -18,5 +18,7 @@
 /**
  * Classes supporting code instrumentation.
  */
+ at NonnullElements
+package org.opensaml.core.metrics;
 
-package org.opensaml.core.metrics;
\ No newline at end of file
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/package-info.java
index b70fecc92..aa910da7c 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Classes at the most general level of the library. */
-package org.opensaml.core;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObject.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObject.java
index fa6d59c62..4acc4454b 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObject.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObject.java
@@ -25,6 +25,7 @@ import javax.xml.namespace.QName;
 
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
 
+import net.shibboleth.shared.annotation.constraint.Live;
 import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.annotation.constraint.Unmodifiable;
 import net.shibboleth.shared.collection.CollectionSupport;
@@ -58,12 +59,14 @@ public abstract class AbstractElementExtensibleXMLObject extends AbstractXMLObje
     }
 
     /** {@inheritDoc} */
-    @Nonnull public List<XMLObject> getUnknownXMLObjects() {
+    @Nonnull @Live public List<XMLObject> getUnknownXMLObjects() {
         return anyXMLObjects;
     }
 
     /** {@inheritDoc} */
-    @Nonnull public List<XMLObject> getUnknownXMLObjects(@Nonnull final QName typeOrName) {
+    @SuppressWarnings("unchecked")
+    @Nonnull @Live public List<XMLObject> getUnknownXMLObjects(@Nonnull final QName typeOrName) {
         return (List<XMLObject>) anyXMLObjects.subList(typeOrName);
     }
+
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObjectMarshaller.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObjectMarshaller.java
index b6d97c0e8..1984a5126 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObjectMarshaller.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObjectMarshaller.java
@@ -28,11 +28,6 @@ import org.w3c.dom.Element;
  * <code>xs:anyAttribute</code> attributes or text content.
  */
 public abstract class AbstractElementExtensibleXMLObjectMarshaller extends AbstractXMLObjectMarshaller {
-    
-    /** Constructor. */
-    public AbstractElementExtensibleXMLObjectMarshaller(){
-        super();
-    }
 
     /**
      * No <code>xs:anyAttribute</code> attributes.
@@ -53,4 +48,5 @@ public abstract class AbstractElementExtensibleXMLObjectMarshaller extends Abstr
     protected void marshallElementContent(@Nonnull final XMLObject xmlObject, @Nonnull final Element domElement)
             throws MarshallingException {
     }
+
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObjectUnmarshaller.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObjectUnmarshaller.java
index 6613c875e..194c9ea19 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObjectUnmarshaller.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractElementExtensibleXMLObjectUnmarshaller.java
@@ -28,11 +28,6 @@ import org.w3c.dom.Attr;
  * <code>xs:anyAttribute</code> attributes or text content.
  */
 public abstract class AbstractElementExtensibleXMLObjectUnmarshaller extends AbstractXMLObjectUnmarshaller {
-    
-    /** Constructor. */
-    public AbstractElementExtensibleXMLObjectUnmarshaller(){
-        super();
-    }
 
     /**
      * Unmarshalls all child elements in the <code>xs:any</code> list.
@@ -64,4 +59,5 @@ public abstract class AbstractElementExtensibleXMLObjectUnmarshaller extends Abs
     @Override
     protected void processElementContent(@Nonnull final XMLObject xmlObject, @Nonnull final String elementContent) {
     }
+
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObject.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObject.java
index 2facd6d16..60cc46949 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObject.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObject.java
@@ -49,4 +49,5 @@ public abstract class AbstractExtensibleXMLObject extends AbstractElementExtensi
     @Nonnull public AttributeMap getUnknownAttributes() {
         return anyAttributes;
     }
+    
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObjectMarshaller.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObjectMarshaller.java
index f49d8c86e..93fec2be1 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObjectMarshaller.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObjectMarshaller.java
@@ -28,11 +28,6 @@ import org.w3c.dom.Element;
  * <code>xs:anyAttribute</code> attributes.
  */
 public abstract class AbstractExtensibleXMLObjectMarshaller extends AbstractElementExtensibleXMLObjectMarshaller {
-    
-    /** Constructor. */
-    public AbstractExtensibleXMLObjectMarshaller(){
-        super();
-    }
 
     /**
      * Marshalls the <code>xs:anyAttribute</code> attributes.
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObjectUnmarshaller.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObjectUnmarshaller.java
index 015272fe3..49be0a84b 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObjectUnmarshaller.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractExtensibleXMLObjectUnmarshaller.java
@@ -30,11 +30,6 @@ import net.shibboleth.shared.xml.QNameSupport;
  * <code>xs:anyAttribute</code> attributes.
  */
 public abstract class AbstractExtensibleXMLObjectUnmarshaller extends AbstractElementExtensibleXMLObjectUnmarshaller {
-    
-    /** Constructor. */
-    public AbstractExtensibleXMLObjectUnmarshaller() {
-        super();
-    }
 
     /**
      * Unmarshalls the <code>xs:anyAttribute</code> attributes.
@@ -45,8 +40,7 @@ public abstract class AbstractExtensibleXMLObjectUnmarshaller extends AbstractEl
     protected void processAttribute(@Nonnull final XMLObject xmlObject, @Nonnull final Attr attribute)
             throws UnmarshallingException {
         final AttributeExtensibleXMLObject anyAttribute = (AttributeExtensibleXMLObject) xmlObject;
-        final QName attribQName = QNameSupport.constructQName(attribute.getNamespaceURI(), attribute.getLocalName(),
-                attribute.getPrefix());
+        final QName attribQName = QNameSupport.getNodeQName(attribute);
         if (attribute.isId()) {
             anyAttribute.getUnknownAttributes().registerID(attribQName);
         }
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractXMLObject.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractXMLObject.java
index 320f804a8..40be3adbc 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractXMLObject.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractXMLObject.java
@@ -536,7 +536,7 @@ public abstract class AbstractXMLObject implements XMLObject {
     }
     
     /** {@inheritDoc} */
-    public Boolean isNil() {
+    @Nullable public Boolean isNil() {
         if (nil != null) {
             return nil.getValue();
         }
@@ -545,7 +545,7 @@ public abstract class AbstractXMLObject implements XMLObject {
     }
 
     /** {@inheritDoc} */
-    public XSBooleanValue isNilXSBoolean() {
+    @Nullable public XSBooleanValue isNilXSBoolean() {
         return nil;
     }
 
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractXMLObjectBuilder.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractXMLObjectBuilder.java
index 6b2efd841..540582429 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractXMLObjectBuilder.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AbstractXMLObjectBuilder.java
@@ -23,6 +23,7 @@ import javax.xml.namespace.QName;
 
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.xml.DOMTypeSupport;
+import net.shibboleth.shared.xml.QNameSupport;
 
 import org.w3c.dom.Element;
 
@@ -38,12 +39,14 @@ public abstract class AbstractXMLObjectBuilder<XMLObjectType extends XMLObject>
 
     /** {@inheritDoc} */
     @Nonnull public XMLObjectType buildObject(@Nonnull final QName objectName){
-        return buildObject(objectName.getNamespaceURI(), objectName.getLocalPart(), objectName.getPrefix());
+        return buildObject(objectName.getNamespaceURI(), QNameSupport.ensureLocalPart(objectName),
+                objectName.getPrefix());
     }
     
     /** {@inheritDoc} */
     @Nonnull public XMLObjectType buildObject(@Nonnull final QName objectName, @Nullable final QName schemaType){
-        return buildObject(objectName.getNamespaceURI(), objectName.getLocalPart(), objectName.getPrefix(), schemaType);
+        return buildObject(objectName.getNamespaceURI(), QNameSupport.ensureLocalPart(objectName),
+                objectName.getPrefix(), schemaType);
     }
     
     /** {@inheritDoc} */
@@ -56,22 +59,17 @@ public abstract class AbstractXMLObjectBuilder<XMLObjectType extends XMLObject>
         final XMLObjectType xmlObject;
 
         xmlObject = buildObject(namespaceURI, localName, namespacePrefix);
-        ((AbstractXMLObject) xmlObject).setSchemaType(schemaType);
+        if (xmlObject instanceof AbstractXMLObject downcast) {
+            downcast.setSchemaType(schemaType);
+        }
 
         return xmlObject;
     }
 
     /** {@inheritDoc} */
     @Nonnull public XMLObjectType buildObject(@Nonnull final Element element) {
-        final XMLObjectType xmlObject;
-
-        final String localName = element.getLocalName();
-        final String nsURI = element.getNamespaceURI();
-        final String nsPrefix = element.getPrefix();
         final QName schemaType = DOMTypeSupport.getXSIType(element);
-
-        xmlObject = buildObject(nsURI, localName, nsPrefix, schemaType);
-
-        return xmlObject;
+        return buildObject(QNameSupport.getNodeQName(element), schemaType);
     }
+
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AttributeExtensibleXMLObject.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AttributeExtensibleXMLObject.java
index 26039895b..7ad1a5e46 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/AttributeExtensibleXMLObject.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/AttributeExtensibleXMLObject.java
@@ -33,5 +33,6 @@ public interface AttributeExtensibleXMLObject extends XMLObject {
      * 
      * @return a map of the attributes
      */
-    @Nonnull public AttributeMap getUnknownAttributes();
+    @Nonnull AttributeMap getUnknownAttributes();
+    
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/BaseBearing.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/BaseBearing.java
index 1c665bc4b..7bbfaa4f0 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/BaseBearing.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/BaseBearing.java
@@ -31,10 +31,10 @@ import net.shibboleth.shared.xml.XMLConstants;
 public interface BaseBearing {
 
     /** The <code>base</code> attribute local name. */
-    @Nonnull @NotEmpty public static final String XML_BASE_ATTR_LOCAL_NAME = "base";
+    @Nonnull @NotEmpty static final String XML_BASE_ATTR_LOCAL_NAME = "base";
 
     /** The <code>xml:base</code> qualified attribute name. */
-    @Nonnull public static final QName XML_BASE_ATTR_NAME =
+    @Nonnull static final QName XML_BASE_ATTR_NAME =
         new QName(XMLConstants.XML_NS, XML_BASE_ATTR_LOCAL_NAME, XMLConstants.XML_PREFIX);
 
     /**
@@ -42,13 +42,13 @@ public interface BaseBearing {
      * 
      * @return The <code>@xml:base</code> attribute value or <code>null</code>.
      */
-    @Nullable public String getXMLBase();
+    @Nullable String getXMLBase();
 
     /**
      * Sets the <code>@xml:base</code> attribute value.
      * 
      * @param newBase The <code>@xml:base</code> attribute value
      */
-    public void setXMLBase(@Nullable final String newBase);
+    void setXMLBase(@Nullable final String newBase);
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/ElementExtensibleXMLObject.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/ElementExtensibleXMLObject.java
index b3338c75c..8fc3908d4 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/ElementExtensibleXMLObject.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/ElementExtensibleXMLObject.java
@@ -23,7 +23,6 @@ import javax.annotation.Nonnull;
 import javax.xml.namespace.QName;
 
 import net.shibboleth.shared.annotation.constraint.Live;
-import net.shibboleth.shared.annotation.constraint.NonnullElements;
 
 /**
  * An XMLObject whose content model contains "any" child elements.
@@ -35,7 +34,7 @@ public interface ElementExtensibleXMLObject extends XMLObject {
      * 
      * @return list of XMLObjects added to this XMLObject as part of the "any" content model
      */
-    @Nonnull @NonnullElements @Live public List<XMLObject> getUnknownXMLObjects();
+    @Nonnull @Live List<XMLObject> getUnknownXMLObjects();
     
     /**
      * Gets the list of XMLObjects added to this XMLObject as part of the "any" content model,
@@ -46,5 +45,5 @@ public interface ElementExtensibleXMLObject extends XMLObject {
      * 
      * TODO: think this should be typed List<? extends XMLObject> 
      */
-    @Nonnull @NonnullElements @Live public List<XMLObject> getUnknownXMLObjects(@Nonnull final QName typeOrName);
+    @Nonnull @Live List<XMLObject> getUnknownXMLObjects(@Nonnull final QName typeOrName);
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/IdBearing.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/IdBearing.java
index d7a767667..8018ccd34 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/IdBearing.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/IdBearing.java
@@ -31,10 +31,10 @@ import net.shibboleth.shared.xml.XMLConstants;
 public interface IdBearing {
 
     /** The <code>id</code> attribute local name. */
-    @Nonnull @NotEmpty public static final String XML_ID_ATTR_LOCAL_NAME = "id";
+    @Nonnull @NotEmpty static final String XML_ID_ATTR_LOCAL_NAME = "id";
 
     /** The <code>xml:id</code> qualified attribute name. */
-    @Nonnull public static final QName XML_ID_ATTR_NAME =
+    @Nonnull static final QName XML_ID_ATTR_NAME =
         new QName(XMLConstants.XML_NS, XML_ID_ATTR_LOCAL_NAME, XMLConstants.XML_PREFIX);
 
     /**
@@ -42,13 +42,13 @@ public interface IdBearing {
      * 
      * @return The <code>@xml:id</code> attribute value or <code>null</code>.
      */
-    @Nullable public String getXMLId();
+    @Nullable String getXMLId();
 
     /**
      * Sets the <code>@xml:id</code> attribute value.
      * 
      * @param newId The <code>@xml:id</code> attribute value
      */
-    public void setXMLId(@Nullable final String newId);
+    void setXMLId(@Nullable final String newId);
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/LangBearing.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/LangBearing.java
index 0278e0eda..8058f6db4 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/LangBearing.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/LangBearing.java
@@ -31,10 +31,10 @@ import net.shibboleth.shared.xml.XMLConstants;
 public interface LangBearing {
 
     /** The <code>lang</code> attribute local name. */
-    @Nonnull @NotEmpty public static final String XML_LANG_ATTR_LOCAL_NAME = "lang";
+    @Nonnull @NotEmpty static final String XML_LANG_ATTR_LOCAL_NAME = "lang";
 
     /** The <code>xml:lang</code> qualified attribute name. */
-    @Nonnull public static final QName XML_LANG_ATTR_NAME =
+    @Nonnull static final QName XML_LANG_ATTR_NAME =
         new QName(XMLConstants.XML_NS, XML_LANG_ATTR_LOCAL_NAME, XMLConstants.XML_PREFIX);
 
     /**
@@ -42,13 +42,13 @@ public interface LangBearing {
      * 
      * @return The <code>@xml:lang</code> attribute value or <code>null</code>.
      */
-    @Nullable public String getXMLLang();
+    @Nullable String getXMLLang();
 
     /**
      * Sets the <code>@xml:lang</code> attribute value.
      * 
      * @param newLang The <code>@xml:lang</code> attribute value
      */
-    public void setXMLLang(@Nullable final String newLang);
+    void setXMLLang(@Nullable final String newLang);
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/Namespace.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/Namespace.java
index b92cef800..1ebd75dbe 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/Namespace.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/Namespace.java
@@ -19,6 +19,7 @@ package org.opensaml.core.xml;
 
 import java.util.Objects;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.shared.primitive.StringSupport;
@@ -28,13 +29,13 @@ import net.shibboleth.shared.xml.XMLConstants;
 public class Namespace {
 
     /** URI of the namespace. */
-    private String namespaceURI;
+    @Nullable private String namespaceURI;
 
     /** Prefix of the namespace. */
-    private String namespacePrefix;
+    @Nullable private String namespacePrefix;
 
     /** String representation of this namespace. */
-    private String nsStr;
+    @Nullable private String nsStr;
 
     /**
      * Constructor.
@@ -53,7 +54,7 @@ public class Namespace {
      * 
      * @return the prefix of the namespace, may be null if this is a default namespace
      */
-    public String getNamespacePrefix() {
+    @Nullable public String getNamespacePrefix() {
         return namespacePrefix;
     }
 
@@ -62,9 +63,23 @@ public class Namespace {
      * 
      * @return the URI of the namespace
      */
-    public String getNamespaceURI() {
+    @Nullable public String getNamespaceURI() {
         return namespaceURI;
     }
+    
+    /**
+     * Get the URI of the namespace, raising an {@link IllegalStateException} if null.
+     * 
+     * @return namespace URI
+     * 
+     * @since 5.0.0
+     */
+    @Nonnull public String ensureNamespaceURI() {
+        if (namespaceURI != null) {
+            return namespaceURI;
+        }
+        throw new IllegalStateException("Namespace URI was not set");
+    }
 
     /** {@inheritDoc} */
     @Override
@@ -135,4 +150,5 @@ public class Namespace {
 
         nsStr = stringRep.toString();
     }
+    
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/NamespaceManager.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/NamespaceManager.java
index 778466b16..b71600683 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/NamespaceManager.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/NamespaceManager.java
@@ -26,7 +26,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.xml.namespace.QName;
 
-import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.Live;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.annotation.constraint.Unmodifiable;
@@ -79,7 +79,7 @@ public class NamespaceManager {
     @Nonnull private final Map<String, Namespace> attrValues;
     
     /** Registered namespaces of content values. */
-    private Namespace contentValue;
+    @Nullable private Namespace contentValue;
     
     /**
      * Constructor.
@@ -102,6 +102,7 @@ public class NamespaceManager {
      * @param name attribute name as a QName
      * @return a string attribute ID
      */
+    @SuppressWarnings("null")
     @Nonnull @NotEmpty public static String generateAttributeID(@Nonnull final QName name) {
        return name.toString(); 
     }
@@ -120,7 +121,7 @@ public class NamespaceManager {
      * 
      * @return the unmodifiable set of namespaces
      */
-    @Nonnull @NonnullElements @Unmodifiable @NotLive public Set<Namespace> getNamespaces() {
+    @Nonnull @Unmodifiable @NotLive public Set<Namespace> getNamespaces() {
         final Set<Namespace> namespaces = mergeNamespaceCollections(decls, attrNames, attrValues.values());
         addNamespace(namespaces, getElementNameNamespace());
         addNamespace(namespaces, getElementTypeNamespace());
@@ -151,7 +152,7 @@ public class NamespaceManager {
      * 
      * @return the set of namespace declarations
      */
-    @Nonnull @NonnullElements @Unmodifiable @NotLive public Set<Namespace> getNamespaceDeclarations() {
+    @Nonnull @Unmodifiable @NotLive public Set<Namespace> getNamespaceDeclarations() {
         return CollectionSupport.copyToSet(decls);
     }
     
@@ -228,7 +229,7 @@ public class NamespaceManager {
      * 
      * @return the set of non-visibly used namespace prefixes
      */
-    @Nonnull public Set<String> getNonVisibleNamespacePrefixes() {
+    @Nonnull @Unmodifiable @NotLive public Set<String> getNonVisibleNamespacePrefixes() {
         final LazySet<String> prefixes = new LazySet<>();
         addPrefixes(prefixes, getNonVisibleNamespaces());
         return prefixes;
@@ -245,7 +246,7 @@ public class NamespaceManager {
      * 
      * @return the set of non-visibly used namespaces 
      */
-    @Nonnull public Set<Namespace> getNonVisibleNamespaces() {
+    @Nonnull @Unmodifiable @NotLive public Set<Namespace> getNonVisibleNamespaces() {
         final LazySet<Namespace> nonVisibleCandidates = new LazySet<>();
 
         // Collect each child's non-visible namespaces
@@ -283,13 +284,14 @@ public class NamespaceManager {
      * 
      * @return set of all namespaces in scope for the owning object
      */
-    @Nonnull public Set<Namespace> getAllNamespacesInSubtreeScope() {
+    @Nonnull @Unmodifiable @NotLive public Set<Namespace> getAllNamespacesInSubtreeScope() {
         final LazySet<Namespace> namespaces = new LazySet<>();
 
         // Collect namespaces for the subtree rooted at each child
         final List<XMLObject> children = getOwner().getOrderedChildren();
         if (children != null) {
-            for(final XMLObject child : children) {
+            for (final XMLObject child : children) {
+                // TODO: This check isn't necessary by spec, but we have XACML code still including null elements.
                 if (child != null) {
                     final Set<Namespace> childNamespaces = child.getNamespaceManager().getAllNamespacesInSubtreeScope();
                     if (!childNamespaces.isEmpty()) {
@@ -380,7 +382,7 @@ public class NamespaceManager {
      * @param namespaces the set of namespaces
      * @param newNamespace the namespace to add to the set
      */
-    private void addNamespace(@Nonnull final Set<Namespace> namespaces, @Nullable final Namespace newNamespace) {
+    private void addNamespace(@Nonnull @Live final Set<Namespace> namespaces, @Nullable final Namespace newNamespace) {
         if (newNamespace == null) {
             return;
         }
@@ -394,7 +396,8 @@ public class NamespaceManager {
      * @param namespaces the set of namespaces
      * @param oldNamespace the namespace to add to the set
      */
-    private void removeNamespace(@Nonnull final Set<Namespace> namespaces, @Nullable final Namespace oldNamespace) {
+    private void removeNamespace(@Nonnull @Live final Set<Namespace> namespaces,
+            @Nullable final Namespace oldNamespace) {
         if (oldNamespace == null) {
             return;
         }
@@ -409,7 +412,8 @@ public class NamespaceManager {
      * @return the a new set of merged Namespaces
      */
     @SafeVarargs
-    @Nonnull private Set<Namespace> mergeNamespaceCollections(final Collection<Namespace> ... namespaces) {
+    @Nonnull @Unmodifiable @NotLive private Set<Namespace> mergeNamespaceCollections(
+            @Nonnull final Collection<Namespace> ... namespaces) {
         final LazySet<Namespace> newNamespaces = new LazySet<>();
         
         for (final Collection<Namespace> nsCollection : namespaces) {
@@ -429,7 +433,7 @@ public class NamespaceManager {
      * 
      * @return the set of visibly-used namespaces
      */
-    @Nonnull private Set<Namespace> getVisibleNamespaces() {
+    @Nonnull @Unmodifiable @NotLive private Set<Namespace> getVisibleNamespaces() {
         final LazySet<Namespace> namespaces = new LazySet<>();
 
         // Add namespace from element name.
@@ -458,7 +462,7 @@ public class NamespaceManager {
      * 
      * @return the set of non-visibly-used namespaces
      */
-    @Nonnull private Set<Namespace> getNonVisibleNamespaceCandidates() {
+    @Nonnull @Unmodifiable @NotLive private Set<Namespace> getNonVisibleNamespaceCandidates() {
         final LazySet<Namespace> namespaces = new LazySet<>();
 
         // Add xsi:type value's prefix, if element carries an xsi:type
@@ -487,7 +491,8 @@ public class NamespaceManager {
      * @param prefixes the set of prefixes to which to add
      * @param namespaces the source set of Namespaces
      */
-    private void addPrefixes(@Nonnull final Set<String> prefixes, @Nonnull final Collection<Namespace> namespaces) {
+    private void addPrefixes(@Nonnull @Live final Set<String> prefixes,
+            @Nonnull final Collection<Namespace> namespaces) {
         for (final Namespace ns : namespaces) {
             String prefix = StringSupport.trimOrNull(ns.getNamespacePrefix());
             if (prefix == null) {
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/SpaceBearing.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/SpaceBearing.java
index 5cade4448..652b85688 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/SpaceBearing.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/SpaceBearing.java
@@ -31,7 +31,7 @@ import net.shibboleth.shared.xml.XMLConstants;
 public interface SpaceBearing {
     
     /** Enum representing the allowed values of the xml:space attribute. */
-    public enum XMLSpaceEnum {
+    enum XMLSpaceEnum {
         /** xml:space value "default". */
         DEFAULT,
         /** xml:space value "preserve". */
@@ -63,10 +63,10 @@ public interface SpaceBearing {
     }
 
     /** The <code>space</code> attribute local name. */
-    @Nonnull @NotEmpty public static final String XML_SPACE_ATTR_LOCAL_NAME = "space";
+    @Nonnull @NotEmpty static final String XML_SPACE_ATTR_LOCAL_NAME = "space";
 
     /** The <code>xml:space</code> qualified attribute name. */
-    @Nonnull public static final QName XML_SPACE_ATTR_NAME =
+    @Nonnull static final QName XML_SPACE_ATTR_NAME =
         new QName(XMLConstants.XML_NS, XML_SPACE_ATTR_LOCAL_NAME, XMLConstants.XML_PREFIX);
 
     /**
@@ -74,13 +74,13 @@ public interface SpaceBearing {
      * 
      * @return The <code>@xml:space</code> attribute value or <code>null</code>.
      */
-    @Nullable public XMLSpaceEnum getXMLSpace();
+    @Nullable XMLSpaceEnum getXMLSpace();
 
     /**
      * Sets the <code>@xml:space</code> attribute value.
      * 
      * @param newSpace The <code>@xml:space</code> attribute value
      */
-    public void setXMLSpace(@Nullable final XMLSpaceEnum newSpace);
+    void setXMLSpace(@Nullable final XMLSpaceEnum newSpace);
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/XMLObjectBuilder.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/XMLObjectBuilder.java
index 7e6dbd3b0..e1560fcfc 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/XMLObjectBuilder.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/XMLObjectBuilder.java
@@ -37,7 +37,7 @@ public interface XMLObjectBuilder<XMLObjectType extends XMLObject> {
      * 
      * @return the constructed XMLObject
      */
-    @Nonnull public XMLObjectType buildObject(@Nonnull final QName objectName);
+    @Nonnull XMLObjectType buildObject(@Nonnull final QName objectName);
     
     /**
      * Creates an XMLObject with a given fully qualified name and schema type.
@@ -47,7 +47,7 @@ public interface XMLObjectBuilder<XMLObjectType extends XMLObject> {
      * 
      * @return the constructed XMLObject
      */
-    @Nonnull public XMLObjectType buildObject(@Nonnull final QName objectName, @Nullable final QName schemaType);
+    @Nonnull XMLObjectType buildObject(@Nonnull final QName objectName, @Nullable final QName schemaType);
 
     /**
      * Creates an XMLObject with a given fully qualified name.
@@ -58,7 +58,7 @@ public interface XMLObjectBuilder<XMLObjectType extends XMLObject> {
      * 
      * @return the constructed XMLObject
      */
-    @Nonnull public XMLObjectType buildObject(@Nullable final String namespaceURI, @Nonnull final String localName,
+    @Nonnull XMLObjectType buildObject(@Nullable final String namespaceURI, @Nonnull final String localName,
             @Nullable final String namespacePrefix);
 
     /**
@@ -71,7 +71,7 @@ public interface XMLObjectBuilder<XMLObjectType extends XMLObject> {
      * 
      * @return the constructed XMLObject
      */
-    @Nonnull public XMLObjectType buildObject(@Nullable final String namespaceURI, @Nonnull final String localName,
+    @Nonnull XMLObjectType buildObject(@Nullable final String namespaceURI, @Nonnull final String localName,
             @Nullable final String namespacePrefix, @Nullable final QName schemaType);
 
     /**
@@ -84,5 +84,6 @@ public interface XMLObjectBuilder<XMLObjectType extends XMLObject> {
      * 
      * @return the constructed XMLObject
      */
-    @Nonnull public XMLObjectType buildObject(@Nonnull final Element element);
+    @Nonnull XMLObjectType buildObject(@Nonnull final Element element);
+    
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/config/XMLObjectProviderRegistrySupport.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/config/XMLObjectProviderRegistrySupport.java
index 3af160e10..05d2091f9 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/config/XMLObjectProviderRegistrySupport.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/config/XMLObjectProviderRegistrySupport.java
@@ -32,10 +32,10 @@ import org.opensaml.core.xml.io.UnmarshallerFactory;
 import net.shibboleth.shared.xml.ParserPool;
 
 /** Class for loading library configuration files and retrieving the configured components. */
-public class XMLObjectProviderRegistrySupport {
+public final class XMLObjectProviderRegistrySupport {
 
     /** Constructor. */
-    protected XMLObjectProviderRegistrySupport() {
+    private XMLObjectProviderRegistrySupport() {
 
     }
     
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/config/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/config/package-info.java
index dc7513653..aba22a8a3 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/config/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/config/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Configuration of XML object providers and related functionality. */
-package org.opensaml.core.xml.config;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core.xml.config;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/AbstractXMLObjectMarshaller.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/AbstractXMLObjectMarshaller.java
index 60ce9a2d1..edf03fa62 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/AbstractXMLObjectMarshaller.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/AbstractXMLObjectMarshaller.java
@@ -308,14 +308,14 @@ public abstract class AbstractXMLObjectMarshaller implements Marshaller {
                 final String declared = NamespaceSupport.lookupNamespaceURI(domElement, null, 
                         namespace.getNamespacePrefix());
                 log.trace("Lookup of prefix '{}' returned '{}'", namespace.getNamespacePrefix(),  declared);
-                if (declared != null && namespace.getNamespaceURI().equals(declared)) {
+                if (declared != null && declared.equals(namespace.getNamespaceURI())) {
                     log.trace("Namespace {} has already been declared on an ancestor of {} no need to add it here", 
                             namespace, xmlObject.getElementQName());
                     continue;
                 }
             }
             log.trace("Adding namespace declaration {} to {}", namespace, xmlObject.getElementQName());
-            NamespaceSupport.appendNamespaceDeclaration(domElement, namespace.getNamespaceURI(),
+            NamespaceSupport.appendNamespaceDeclaration(domElement, namespace.ensureNamespaceURI(),
                     namespace.getNamespacePrefix());
         }
     }
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/MarshallerFactory.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/MarshallerFactory.java
index 999ba96dd..f05c60f13 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/MarshallerFactory.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/MarshallerFactory.java
@@ -28,6 +28,8 @@ import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.XMLRuntimeException;
 import org.slf4j.Logger;
 
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -130,7 +132,7 @@ public class MarshallerFactory {
      * 
      * @return a listing of all the Marshallers currently registered
      */
-    @Nonnull public Map<QName, Marshaller> getMarshallers() {
+    @Nonnull @Unmodifiable @NotLive public Map<QName, Marshaller> getMarshallers() {
         return CollectionSupport.copyToMap(marshallers);
     }
 
@@ -160,4 +162,5 @@ public class MarshallerFactory {
         log.debug("Deregistering marshaller for object type {}", key);
         return marshallers.remove(key);
     }
+    
 }
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/UnmarshallerFactory.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/UnmarshallerFactory.java
index ababb8012..de151cd65 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/UnmarshallerFactory.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/UnmarshallerFactory.java
@@ -24,6 +24,8 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.xml.namespace.QName;
 
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -133,7 +135,7 @@ public class UnmarshallerFactory {
      * 
      * @return a listing of all the Unmarshallers currently registered
      */
-    @Nonnull public Map<QName, Unmarshaller> getUnmarshallers() {
+    @Nonnull @Unmodifiable @NotLive public Map<QName, Unmarshaller> getUnmarshallers() {
         return CollectionSupport.copyToMap(unmarshallers);
     }
 
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/package-info.java
index c3956d2f1..2258727a0 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/io/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Interfaces and abstract implementations of marshallers and unmarshallers. */
-package org.opensaml.core.xml.io;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core.xml.io;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/package-info.java
index 3c946b494..1c098836b 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Base classes for working with XML as Java objects and configuring the library. */
-package org.opensaml.core.xml;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core.xml;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/AbstractConditionalLoadXMLObjectLoadSaveManager.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/AbstractConditionalLoadXMLObjectLoadSaveManager.java
index 35b1c1c13..0798196d3 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/AbstractConditionalLoadXMLObjectLoadSaveManager.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/AbstractConditionalLoadXMLObjectLoadSaveManager.java
@@ -45,7 +45,7 @@ public abstract class AbstractConditionalLoadXMLObjectLoadSaveManager<T extends
     private boolean loadConditionally;
     
     /** Storage for last modified time of requested data. */
-    private Map<String,Instant> loadLastModified;
+    @Nonnull private Map<String,Instant> loadLastModified;
     
     /** 
      * Constructor. 
@@ -118,4 +118,4 @@ public abstract class AbstractConditionalLoadXMLObjectLoadSaveManager<T extends
      */
     protected abstract boolean isUnmodifiedSinceLastLoad(@Nonnull final String key) throws IOException;
     
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/FilesystemLoadSaveManager.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/FilesystemLoadSaveManager.java
index bae36fb12..b21b467a5 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/FilesystemLoadSaveManager.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/FilesystemLoadSaveManager.java
@@ -43,14 +43,17 @@ import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.core.xml.util.XMLObjectSource;
 import org.opensaml.core.xml.util.XMLObjectSupport;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.common.io.ByteStreams;
 import com.google.common.io.Files;
 
 import net.shibboleth.shared.annotation.ParameterName;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.collection.Pair;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 import net.shibboleth.shared.xml.ParserPool;
 import net.shibboleth.shared.xml.XMLParserException;
@@ -72,17 +75,17 @@ import net.shibboleth.shared.xml.XMLParserException;
 public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractConditionalLoadXMLObjectLoadSaveManager<T> {
     
     /** Logger. */
-    private Logger log = LoggerFactory.getLogger(FilesystemLoadSaveManager.class);
+    @Nonnull private Logger log = LoggerFactory.getLogger(FilesystemLoadSaveManager.class);
     
     /** The base directory used for storing individual serialized XML files. */
-    private File baseDirectory;
+    @Nonnull private File baseDirectory;
     
     /** Optional strategy function which produces the intermediate directory path(s) between
      * the <code>baseDirectory</code> and the actual file. */
-    private Function<String, List<String>> intermediateDirectoryStrategy;
+    @Nullable private Function<String, List<String>> intermediateDirectoryStrategy;
 
     /** Parser pool instance for deserializing XML from the filesystem. */
-    private ParserPool parserPool;
+    @Nonnull private ParserPool parserPool;
     
     /**
      * Constructor.
@@ -252,8 +255,9 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
             Constraint.isTrue(baseDirectory.mkdirs(), "Base directory did not exist and could not be created");
         }
         
-        parserPool = pp;
-        if (parserPool == null) {
+        if (pp != null) {
+            parserPool = pp;
+        } else {
             parserPool = Constraint.isNotNull(XMLObjectProviderRegistrySupport.getParserPool(),
                     "Specified ParserPool was null and global ParserPool was not available");
         }
@@ -262,26 +266,26 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
     }
 
     /** {@inheritDoc} */
-    @Nonnull public Set<String> listKeys() throws IOException {
+    @Nonnull @NotLive @Unmodifiable public Set<String> listKeys() throws IOException {
         return java.nio.file.Files.walk(baseDirectory.toPath())
                 .filter(java.nio.file.Files::isRegularFile)
                 .map(Path::getFileName)
                 .map(Path::toString)
-                .collect(Collectors.toUnmodifiableSet());
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableSet())).get();
     }
 
     /** {@inheritDoc} */
-    @Nonnull public Iterable<Pair<String, T>> listAll() throws IOException {
+    @Nonnull @NotLive @Unmodifiable public Iterable<Pair<String, T>> listAll() throws IOException {
         return new FileIterable(listKeys());
     }
 
     /** {@inheritDoc} */
-    public boolean exists(final String key) throws IOException {
+    public boolean exists(@Nonnull final String key) throws IOException {
         return buildFile(key).exists();
     }
 
     /** {@inheritDoc} */
-    public T load(final String key) throws IOException {
+    public T load(@Nonnull final String key) throws IOException {
         final File file = buildFile(key);
         if (!file.exists()) {
             log.debug("Target file with key '{}' does not exist, path: {}", key, file.getAbsolutePath());
@@ -317,12 +321,13 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
     }
 
     /** {@inheritDoc} */
-    public void save(final String key, final T xmlObject) throws IOException {
+    public void save(@Nonnull final String key, @Nonnull final T xmlObject) throws IOException {
         save(key, xmlObject, false);
     }
 
     /** {@inheritDoc} */
-    public void save(final String key, final T xmlObject, final boolean overwrite) throws IOException {
+    public void save(@Nonnull final String key, @Nonnull final T xmlObject, final boolean overwrite)
+            throws IOException {
         if (!overwrite && exists(key)) {
             throw new IOException(
                     String.format("Target file already exists for key '%s' and overwrite not indicated", key));
@@ -353,7 +358,7 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
     }
 
     /** {@inheritDoc} */
-    public boolean remove(final String key) throws IOException {
+    public boolean remove(@Nonnull final String key) throws IOException {
         final File file = buildFile(key);
         if (file.exists()) {
             final boolean success = file.delete();
@@ -367,7 +372,7 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
     }
 
     /** {@inheritDoc} */
-    public boolean updateKey(final String currentKey, final String newKey) throws IOException {
+    public boolean updateKey(@Nonnull final String currentKey, @Nonnull final String newKey) throws IOException {
         final File currentFile = buildFile(currentKey);
         if (!currentFile.exists()) {
             return false;
@@ -412,7 +417,7 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
      * @return the constructed File instance for the target file
      * @throws IOException if there is a fatal error constructing or evaluating the candidate target path
      */
-    public File buildFile(final String key) throws IOException {
+    @Nonnull public File buildFile(final String key) throws IOException {
         File parentDirectory = baseDirectory;
         if (intermediateDirectoryStrategy != null) {
             final List<String> intermediateDirs = intermediateDirectoryStrategy.apply(key);
@@ -438,7 +443,7 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
     private class FileIterable implements Iterable<Pair<String, T>> {
         
         /** Snapshot of filesystem keys at time of construction. */
-        private Set<String> keys;
+        @Nonnull private Set<String> keys;
 
         /**
          * Constructor.
@@ -446,7 +451,9 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
          * @param filenames Snapshot of filesystem keys at time of construction
          */
         public FileIterable(@Nonnull final Collection<String> filenames) {
-            keys = filenames.stream().filter(s -> s != null).collect(Collectors.toSet());
+            keys = filenames.stream()
+                    .filter(s -> s != null)
+                    .collect(CollectionSupport.nonnullCollector(Collectors.toSet())).get();
         }
 
         /** {@inheritDoc} */
@@ -462,10 +469,10 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
     private class FileIterator implements Iterator<Pair<String, T>> {
         
         /** Iterator for the keys. */
-        private Iterator<String> keysIter;
+        @Nonnull private Iterator<String> keysIter;
         
         /** Current value to return from next(). */
-        private Pair<String, T> current;
+        @Nullable private Pair<String, T> current;
         
         /**
          * Constructor.
@@ -513,10 +520,11 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
          * 
          * @return the next item for iteration, or null if no more items
          */
-        private Pair<String, T> getNext() {
+        @Nullable private Pair<String, T> getNext() {
             while (keysIter.hasNext()) {
                 final String key = keysIter.next();
                 try {
+                    assert key != null;
                     final T xmlObject = load(key);
                     if (xmlObject != null) {
                         // This is to defensively guard against files being removed after files/keys are enumerated.
@@ -533,4 +541,4 @@ public class FilesystemLoadSaveManager<T extends XMLObject> extends AbstractCond
         
     }
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/MapLoadSaveManager.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/MapLoadSaveManager.java
index 5359b31e9..04a487da7 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/MapLoadSaveManager.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/MapLoadSaveManager.java
@@ -29,11 +29,14 @@ import javax.annotation.concurrent.NotThreadSafe;
 
 import org.opensaml.core.xml.XMLObject;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import net.shibboleth.shared.annotation.ParameterName;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.collection.Pair;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
  * Simple implementation of {@link XMLObjectLoadSaveManager} which uses an in-memory map.
@@ -100,26 +103,28 @@ public class MapLoadSaveManager<T extends XMLObject> extends AbstractConditional
     }
 
     /** {@inheritDoc} */
-    @Nonnull public Set<String> listKeys() throws IOException {
-        return backingMap.keySet();
+    @SuppressWarnings("null")
+    @Nonnull @NotLive @Unmodifiable public Set<String> listKeys() throws IOException {
+        return CollectionSupport.copyToSet(backingMap.keySet());
     }
 
     /** {@inheritDoc} */
-    @Nonnull public Iterable<Pair<String, T>> listAll() throws IOException {
+    @Nonnull @NotLive @Unmodifiable public Iterable<Pair<String, T>> listAll() throws IOException {
         final ArrayList<Pair<String,T>> list = new ArrayList<>();
         for (final String key : listKeys()) {
+            assert key != null;
             list.add(new Pair<>(key, load(key)));
         }
-        return list;
+        return CollectionSupport.copyToList(list);
     }
 
     /** {@inheritDoc} */
-    public boolean exists(final String key) throws IOException {
+    public boolean exists(@Nonnull final String key) throws IOException {
         return backingMap.containsKey(key);
     }
 
     /** {@inheritDoc} */
-    public T load(final String key) throws IOException {
+    public T load(@Nonnull final String key) throws IOException {
         if (!exists(key)) {
             log.debug("Target data with key '{}' does not exist", key);
             clearLoadLastModified(key);
@@ -134,12 +139,13 @@ public class MapLoadSaveManager<T extends XMLObject> extends AbstractConditional
     }
 
     /** {@inheritDoc} */
-    public void save(final String key, final T xmlObject) throws IOException {
+    public void save(@Nonnull final String key, @Nonnull final T xmlObject) throws IOException {
         save(key, xmlObject, false);
     }
 
     /** {@inheritDoc} */
-    public void save(final String key, final T xmlObject, final boolean overwrite) throws IOException {
+    public void save(@Nonnull final String key, @Nonnull final T xmlObject, final boolean overwrite)
+            throws IOException {
         if (!overwrite && exists(key)) {
             throw new IOException(String.format("Value already exists for key '%s'", key));
         }
@@ -148,7 +154,7 @@ public class MapLoadSaveManager<T extends XMLObject> extends AbstractConditional
     }
 
     /** {@inheritDoc} */
-    public boolean remove(final String key) throws IOException {
+    public boolean remove(@Nonnull final String key) throws IOException {
         final T removed = backingMap.remove(key);
         dataLastModified.remove(key);
         clearLoadLastModified(key);
@@ -156,7 +162,7 @@ public class MapLoadSaveManager<T extends XMLObject> extends AbstractConditional
     }
 
     /** {@inheritDoc} */
-    public boolean updateKey(final String currentKey, final String newKey) throws IOException {
+    public boolean updateKey(@Nonnull final String currentKey, @Nonnull final String newKey) throws IOException {
         final T value = backingMap.get(currentKey);
         if (value == null) {
             return false;
@@ -184,4 +190,4 @@ public class MapLoadSaveManager<T extends XMLObject> extends AbstractConditional
                 && !lastModified.isAfter(getLoadLastModified(key));
     }
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/XMLObjectLoadSaveManager.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/XMLObjectLoadSaveManager.java
index 0ae5baee6..b4901a78b 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/XMLObjectLoadSaveManager.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/XMLObjectLoadSaveManager.java
@@ -25,7 +25,6 @@ import javax.annotation.Nullable;
 
 import org.opensaml.core.xml.XMLObject;
 
-import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.annotation.constraint.Unmodifiable;
@@ -50,7 +49,7 @@ public interface XMLObjectLoadSaveManager<T extends XMLObject> {
      * 
      * @throws IOException if there is a fatal error obtaining the keys
      */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable Set<String> listKeys() throws IOException;
+    @Nonnull @NotLive @Unmodifiable Set<String> listKeys() throws IOException;
 
     /**
      * Return an iterable of all objects under management, along with their associated index key.
@@ -59,7 +58,7 @@ public interface XMLObjectLoadSaveManager<T extends XMLObject> {
      * 
      * @throws IOException if there is a fatal error loading the managed objects
      */
-    @Nonnull @NonnullElements Iterable<Pair<String,T>> listAll() throws IOException;
+    @Nonnull @NotLive @Unmodifiable Iterable<Pair<String,T>> listAll() throws IOException;
 
     /**
      * Evaluate whether an object already exists indexed by the supplied key.
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/package-info.java
index a86dab33c..aeef35fef 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/persist/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Components for persisting XMLObjects. */
-package org.opensaml.core.xml.persist;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core.xml.persist;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/schema/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/schema/package-info.java
index 317aeb2b5..485ece5a4 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/schema/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/schema/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Interfaces for XMLObjects that represent XML schema types. */
-package org.opensaml.core.xml.schema;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core.xml.schema;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/AttributeMap.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/AttributeMap.java
index 1fa01d29c..7edee0d5f 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/AttributeMap.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/AttributeMap.java
@@ -87,6 +87,7 @@ public class AttributeMap implements Map<QName, String> {
     /** {@inheritDoc} */
     public String put(final QName attributeName, final String value) {
         Constraint.isNotNull(attributeName, "Attribute name cannot be null");
+        assert attributeName != null;
         final String oldValue = get(attributeName);
         if (!Objects.equals(value, oldValue)) {
             releaseDOM();
@@ -120,6 +121,7 @@ public class AttributeMap implements Map<QName, String> {
      */
     public QName put(final QName attributeName, final QName value) {
         Constraint.isNotNull(attributeName, "Attribute name cannot be null");
+        assert attributeName != null;
         final String oldValueString = get(attributeName);
         
         QName oldValue = null;
@@ -194,6 +196,7 @@ public class AttributeMap implements Map<QName, String> {
         if (removedValue != null) {
             releaseDOM();
             final QName attributeName = (QName) key;
+            assert attributeName != null;
             if (isIDAttribute(attributeName) || XMLObjectProviderRegistrySupport.isIDAttribute(attributeName)) {
                 attributeOwner.getIDIndex().deregisterIDMapping(removedValue);
             }
@@ -509,7 +512,7 @@ public class AttributeMap implements Map<QName, String> {
      * @param attributeValue the QName to process
      * @return the attribute value string representation of the QName
      */
-    private String constructAttributeValue(@Nonnull final QName attributeValue) {
+    @Nullable private String constructAttributeValue(@Nonnull final QName attributeValue) {
         final String trimmedLocalName = StringSupport.trimOrNull(attributeValue.getLocalPart());
 
         if (trimmedLocalName == null) {
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/IDIndex.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/IDIndex.java
index 3c430cde3..98f21d47c 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/IDIndex.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/IDIndex.java
@@ -25,6 +25,8 @@ import javax.annotation.Nullable;
 import javax.annotation.concurrent.NotThreadSafe;
 
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.collection.LazyMap;
 import net.shibboleth.shared.logic.Constraint;
@@ -149,7 +151,8 @@ public class IDIndex {
      * 
      * @return the set of ID strings which are keys to the index
      */
-    @Nonnull public Set<String> getIDs() {
+    @SuppressWarnings("null")
+    @Nonnull @Unmodifiable @NotLive public Set<String> getIDs() {
         return CollectionSupport.copyToSet(idMappings.keySet());
     }
     
@@ -158,7 +161,7 @@ public class IDIndex {
      * 
      * @return the ID-to-XMLObject mapping
      */
-    @Nonnull protected Map<String, XMLObject> getIDMappings() {
+    @Nonnull @Unmodifiable @NotLive protected Map<String, XMLObject> getIDMappings() {
         return CollectionSupport.copyToMap(idMappings);
     }
     
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLAttributeSupport.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLAttributeSupport.java
index 613dba43e..f55e83db0 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLAttributeSupport.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLAttributeSupport.java
@@ -17,6 +17,9 @@
 
 package org.opensaml.core.xml.util;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
 import org.opensaml.core.xml.AttributeExtensibleXMLObject;
 import org.opensaml.core.xml.BaseBearing;
 import org.opensaml.core.xml.IdBearing;
@@ -50,12 +53,11 @@ public final class XMLAttributeSupport {
      * @param xmlObject the XML object to which to add the attribute
      * @param id the Id value
      */
-    public static void addXMLId(final XMLObject xmlObject, final String id) {
-        if (xmlObject instanceof IdBearing) {
-            ((IdBearing)xmlObject).setXMLId(id);
-        } else if (xmlObject instanceof AttributeExtensibleXMLObject) {
-            ((AttributeExtensibleXMLObject)xmlObject).getUnknownAttributes()
-                .put(IdBearing.XML_ID_ATTR_NAME, id);
+    public static void addXMLId(@Nonnull final XMLObject xmlObject, @Nullable final String id) {
+        if (xmlObject instanceof IdBearing downcast) {
+            downcast.setXMLId(id);
+        } else if (xmlObject instanceof AttributeExtensibleXMLObject downcast) {
+            downcast.getUnknownAttributes().put(IdBearing.XML_ID_ATTR_NAME, id);
         } else {
             throw new IllegalArgumentException("Specified object was neither IdBearing nor AttributeExtensible");
         }
@@ -68,18 +70,15 @@ public final class XMLAttributeSupport {
      * 
      * @return the value of the xml:id attribute, or null if not present
      */
-    public static String getXMLId(final XMLObject xmlObject) {
-        String value = null;
-        if (xmlObject instanceof IdBearing) {
-            value = StringSupport.trimOrNull(((IdBearing)xmlObject).getXMLId());
+    @Nullable public static String getXMLId(@Nonnull final XMLObject xmlObject) {
+        if (xmlObject instanceof IdBearing downcast) {
+            final String value = StringSupport.trimOrNull(downcast.getXMLId());
             if (value != null) {
                 return value;
             }
         }
-        if (xmlObject instanceof AttributeExtensibleXMLObject) {
-            value = StringSupport.trimOrNull(((AttributeExtensibleXMLObject)xmlObject)
-                        .getUnknownAttributes().get(IdBearing.XML_ID_ATTR_NAME));
-            return value;
+        if (xmlObject instanceof AttributeExtensibleXMLObject downcast) {
+            return StringSupport.trimOrNull(downcast.getUnknownAttributes().get(IdBearing.XML_ID_ATTR_NAME));
         }
         return null;
     }
@@ -90,12 +89,11 @@ public final class XMLAttributeSupport {
      * @param xmlObject the XML object to which to add the attribute
      * @param lang the lang value
      */
-    public static void addXMLLang(final XMLObject xmlObject, final String lang) {
-        if (xmlObject instanceof LangBearing) {
-            ((LangBearing)xmlObject).setXMLLang(lang);
-        } else if (xmlObject instanceof AttributeExtensibleXMLObject) {
-            ((AttributeExtensibleXMLObject)xmlObject).getUnknownAttributes()
-                .put(LangBearing.XML_LANG_ATTR_NAME, lang);
+    public static void addXMLLang(@Nonnull final XMLObject xmlObject, @Nullable final String lang) {
+        if (xmlObject instanceof LangBearing downcast) {
+            downcast.setXMLLang(lang);
+        } else if (xmlObject instanceof AttributeExtensibleXMLObject downcast) {
+            downcast.getUnknownAttributes().put(LangBearing.XML_LANG_ATTR_NAME, lang);
         } else {
             throw new IllegalArgumentException("Specified object was neither LangBearing nor AttributeExtensible");
         }
@@ -108,17 +106,16 @@ public final class XMLAttributeSupport {
      * 
      * @return the value of the xml:lang attribute, or null if not present
      */
-    public static String getXMLLang(final XMLObject xmlObject) {
+    @Nullable public static String getXMLLang(@Nonnull final XMLObject xmlObject) {
         String value = null;
-        if (xmlObject instanceof LangBearing) {
-            value = StringSupport.trimOrNull(((LangBearing)xmlObject).getXMLLang());
+        if (xmlObject instanceof LangBearing downcast) {
+            value = StringSupport.trimOrNull(downcast.getXMLLang());
             if (value != null) {
                 return value;
             }
         }
-        if (xmlObject instanceof AttributeExtensibleXMLObject) {
-            value = StringSupport.trimOrNull(((AttributeExtensibleXMLObject)xmlObject)
-                        .getUnknownAttributes().get(LangBearing.XML_LANG_ATTR_NAME));
+        if (xmlObject instanceof AttributeExtensibleXMLObject downcast) {
+            value = StringSupport.trimOrNull(downcast.getUnknownAttributes().get(LangBearing.XML_LANG_ATTR_NAME));
             return value;
         }
         return null;
@@ -130,12 +127,11 @@ public final class XMLAttributeSupport {
      * @param xmlObject the XML object to which to add the attribute
      * @param base the base value
      */
-    public static void addXMLBase(final XMLObject xmlObject, final String base) {
-        if (xmlObject instanceof BaseBearing) {
-            ((BaseBearing)xmlObject).setXMLBase(base);
-        } else if (xmlObject instanceof AttributeExtensibleXMLObject) {
-            ((AttributeExtensibleXMLObject)xmlObject).getUnknownAttributes()
-                .put(BaseBearing.XML_BASE_ATTR_NAME, base);
+    public static void addXMLBase(@Nonnull final XMLObject xmlObject, @Nullable final String base) {
+        if (xmlObject instanceof BaseBearing downcast) {
+            downcast.setXMLBase(base);
+        } else if (xmlObject instanceof AttributeExtensibleXMLObject downcast) {
+            downcast.getUnknownAttributes().put(BaseBearing.XML_BASE_ATTR_NAME, base);
         } else {
             throw new IllegalArgumentException("Specified object was neither BaseBearing nor AttributeExtensible");
         }
@@ -148,17 +144,16 @@ public final class XMLAttributeSupport {
      * 
      * @return the value of the xml:base attribute, or null if not present
      */
-    public static String getXMLBase(final XMLObject xmlObject) {
+    @Nullable public static String getXMLBase(@Nonnull final XMLObject xmlObject) {
         String value = null;
-        if (xmlObject instanceof BaseBearing) {
-            value = StringSupport.trimOrNull(((BaseBearing)xmlObject).getXMLBase());
+        if (xmlObject instanceof BaseBearing downcast) {
+            value = StringSupport.trimOrNull(downcast.getXMLBase());
             if (value != null) {
                 return value;
             }
         }
-        if (xmlObject instanceof AttributeExtensibleXMLObject) {
-            value = StringSupport.trimOrNull(((AttributeExtensibleXMLObject)xmlObject)
-                        .getUnknownAttributes().get(BaseBearing.XML_BASE_ATTR_NAME));
+        if (xmlObject instanceof AttributeExtensibleXMLObject downcast) {
+            value = StringSupport.trimOrNull(downcast.getUnknownAttributes().get(BaseBearing.XML_BASE_ATTR_NAME));
             return value;
         }
         return null;
@@ -170,12 +165,11 @@ public final class XMLAttributeSupport {
      * @param xmlObject the XML object to which to add the attribute
      * @param space the space value
      */
-    public static void addXMLSpace(final XMLObject xmlObject, final XMLSpaceEnum space) {
-        if (xmlObject instanceof SpaceBearing) {
-            ((SpaceBearing)xmlObject).setXMLSpace(space);
-        } else if (xmlObject instanceof AttributeExtensibleXMLObject) {
-            ((AttributeExtensibleXMLObject)xmlObject).getUnknownAttributes()
-                .put(SpaceBearing.XML_SPACE_ATTR_NAME, space.toString());
+    public static void addXMLSpace(@Nonnull final XMLObject xmlObject, @Nonnull final XMLSpaceEnum space) {
+        if (xmlObject instanceof SpaceBearing downcast) {
+            downcast.setXMLSpace(space);
+        } else if (xmlObject instanceof AttributeExtensibleXMLObject downcast) {
+            downcast.getUnknownAttributes().put(SpaceBearing.XML_SPACE_ATTR_NAME, space.toString());
         } else {
             throw new IllegalArgumentException("Specified object was neither SpaceBearing nor AttributeExtensible");
         }
@@ -188,22 +182,23 @@ public final class XMLAttributeSupport {
      * 
      * @return the value of the xml:space attribute, or null if not present
      */
-    public static XMLSpaceEnum getXMLSpace(final XMLObject xmlObject) {
+    @Nullable public static XMLSpaceEnum getXMLSpace(@Nonnull final XMLObject xmlObject) {
         XMLSpaceEnum valueEnum = null;
-        if (xmlObject instanceof SpaceBearing) {
-            valueEnum = ((SpaceBearing)xmlObject).getXMLSpace();
+        if (xmlObject instanceof SpaceBearing downcast) {
+            valueEnum = downcast.getXMLSpace();
             if (valueEnum != null) {
                 return valueEnum;
             }
         }
         String valueString = null;
-        if (xmlObject instanceof AttributeExtensibleXMLObject) {
-            valueString = StringSupport.trimOrNull(((AttributeExtensibleXMLObject)xmlObject)
-                        .getUnknownAttributes().get(SpaceBearing.XML_SPACE_ATTR_NAME));
+        if (xmlObject instanceof AttributeExtensibleXMLObject downcast) {
+            valueString = StringSupport.trimOrNull(downcast.getUnknownAttributes().get(
+                    SpaceBearing.XML_SPACE_ATTR_NAME));
             if (valueString != null) {
                 return XMLSpaceEnum.parseValue(valueString);
             }
         }
         return null;
     }
-}
+    
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLObjectSource.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLObjectSource.java
index b4e2b8276..0abe723d2 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLObjectSource.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLObjectSource.java
@@ -103,5 +103,4 @@ public class XMLObjectSource {
         }
     }
     
-
-}
+}
\ No newline at end of file
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLObjectSupport.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLObjectSupport.java
index 7858da6e7..15dc28408 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLObjectSupport.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/XMLObjectSupport.java
@@ -31,6 +31,7 @@ import javax.xml.namespace.QName;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 import net.shibboleth.shared.xml.AttributeSupport;
+import net.shibboleth.shared.xml.ElementSupport;
 import net.shibboleth.shared.xml.ParserPool;
 import net.shibboleth.shared.xml.QNameSupport;
 import net.shibboleth.shared.xml.SerializeSupport;
@@ -54,7 +55,6 @@ import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-
 /**
  * A helper class for working with XMLObjects.
  */
@@ -166,6 +166,7 @@ public final class XMLObjectSupport {
                 throw new XMLRuntimeException("Saw unsupported value for CloneOutputOption enum: " + cloneOutputOption);
         }
         
+        assert clonedElement != null;
         final Unmarshaller unmarshaller = getUnmarshaller(clonedElement);
         if (unmarshaller == null) {
             throw new UnmarshallingException("Unable to obtain Unmarshaller for element: "
@@ -196,7 +197,7 @@ public final class XMLObjectSupport {
 
         try {
             final Document messageDoc = parserPool.parse(inputStream);
-            final Element messageElem = messageDoc.getDocumentElement();
+            final Element messageElem = ElementSupport.ensureDocumentElement(messageDoc);
 
             if (LOG.isTraceEnabled()) {
                 LOG.trace("Resultant DOM message was:");
@@ -237,7 +238,7 @@ public final class XMLObjectSupport {
 
         try {
             final Document messageDoc = parserPool.parse(reader);
-            final Element messageElem = messageDoc.getDocumentElement();
+            final Element messageElem = ElementSupport.ensureDocumentElement(messageDoc);
 
             if (LOG.isTraceEnabled()) {
                 LOG.trace("Resultant DOM message was:");
@@ -386,7 +387,7 @@ public final class XMLObjectSupport {
      */
     public static void marshallAttribute(@Nonnull final QName attributeName, @Nullable final String attributeValue,
             @Nonnull final Element domElement, final boolean isIDAttribute) {
-        final Document document = domElement.getOwnerDocument();
+        final Document document = ElementSupport.ensureOwnerDocument(domElement);
         final Attr attribute = AttributeSupport.constructAttribute(document, attributeName);
         attribute.setValue(attributeValue);
         domElement.setAttributeNodeNS(attribute);
@@ -403,14 +404,15 @@ public final class XMLObjectSupport {
      */
     public static void marshallAttributeMap(@Nonnull final AttributeMap attributeMap,
             @Nonnull final Element domElement) {
-        final Document document = domElement.getOwnerDocument();
+        final Document document = ElementSupport.ensureOwnerDocument(domElement);
         Attr attribute = null;
         for (final Entry<QName, String> entry : attributeMap.entrySet()) {
-            attribute = AttributeSupport.constructAttribute(document, entry.getKey());
+            final QName key = entry.getKey();
+            assert key != null;
+            attribute = AttributeSupport.constructAttribute(document, key);
             attribute.setValue(entry.getValue());
             domElement.setAttributeNodeNS(attribute);
-            if (XMLObjectProviderRegistrySupport.isIDAttribute(entry.getKey()) ||
-                    attributeMap.isIDAttribute(entry.getKey())) {
+            if (XMLObjectProviderRegistrySupport.isIDAttribute(key) || attributeMap.isIDAttribute(key)) {
                 domElement.setIdAttributeNode(attribute, true);
             }
         }
@@ -425,6 +427,7 @@ public final class XMLObjectSupport {
     public static void marshallAttributeMapIDness(@Nonnull final AttributeMap attributeMap,
             @Nonnull final Element domElement) {
         for (final QName qname : attributeMap.keySet()) {
+            assert qname != null;
             if (XMLObjectProviderRegistrySupport.isIDAttribute(qname) || attributeMap.isIDAttribute(qname)) {
                 marshallAttributeIDness(qname, domElement, true);
             }
@@ -469,8 +472,7 @@ public final class XMLObjectSupport {
      */
     public static void unmarshallToAttributeMap(@Nonnull final AttributeMap attributeMap,
             @Nonnull final Attr attribute) {
-        final QName attribQName = QNameSupport.constructQName(attribute.getNamespaceURI(), attribute.getLocalName(),
-                attribute.getPrefix());
+        final QName attribQName = QNameSupport.getNodeQName(attribute);
         attributeMap.put(attribQName, attribute.getValue());
         if (attribute.isId() || XMLObjectProviderRegistrySupport.isIDAttribute(attribQName)) {
             attributeMap.registerID(attribQName);
diff --git a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/package-info.java b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/package-info.java
index d059d2f2c..73dbbafe1 100644
--- a/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/package-info.java
+++ b/opensaml-core-api/src/main/java/org/opensaml/core/xml/util/package-info.java
@@ -16,4 +16,7 @@
  */
 
 /** Utility classes for working with XML, XMLObjects, and various data types. */
-package org.opensaml.core.xml.util;
\ No newline at end of file
+ at NonnullElements
+package org.opensaml.core.xml.util;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-core-impl/src/test/java/org/opensaml/core/xml/tests/XMLObjectXSIAttribsTest.java b/opensaml-core-impl/src/test/java/org/opensaml/core/xml/tests/XMLObjectXSIAttribsTest.java
index 724c296a8..0bacc6e83 100644
--- a/opensaml-core-impl/src/test/java/org/opensaml/core/xml/tests/XMLObjectXSIAttribsTest.java
+++ b/opensaml-core-impl/src/test/java/org/opensaml/core/xml/tests/XMLObjectXSIAttribsTest.java
@@ -26,7 +26,6 @@ import org.opensaml.core.xml.XMLObjectBuilder;
 import org.opensaml.core.xml.io.Unmarshaller;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.core.xml.mock.SimpleXMLObject;
-import org.opensaml.core.xml.mock.SimpleXMLObjectBuilder;
 import org.w3c.dom.Document;
 
 import net.shibboleth.shared.xml.XMLParserException;
@@ -54,7 +53,8 @@ public class XMLObjectXSIAttribsTest extends XMLObjectBaseTestCase {
         final SimpleXMLObject sxObject = (SimpleXMLObject) unmarshaller.unmarshall(document.getDocumentElement());
 
         Assert.assertNull(sxObject.isNilXSBoolean());
-        Assert.assertFalse(sxObject.isNil(), "Expected isNil() false");
+        final Boolean nil = sxObject.isNil();
+        Assert.assertTrue(nil != null && !nil, "Expected isNil() false");
     }
     
     @Test
@@ -66,7 +66,8 @@ public class XMLObjectXSIAttribsTest extends XMLObjectBaseTestCase {
         SimpleXMLObject sxObject = (SimpleXMLObject) unmarshaller.unmarshall(document.getDocumentElement());
 
         Assert.assertNotNull(sxObject.isNilXSBoolean());
-        Assert.assertTrue(sxObject.isNil(), "Expected isNil() true");
+        final Boolean nil = sxObject.isNil();
+        Assert.assertTrue(nil != null && nil, "Expected isNil() true");
     }
     
     @Test
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/LocalDynamicMetadataResolverTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/LocalDynamicMetadataResolverTest.java
index d2b2f6a6c..29ee15b56 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/LocalDynamicMetadataResolverTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/LocalDynamicMetadataResolverTest.java
@@ -22,6 +22,8 @@ import java.security.NoSuchAlgorithmException;
 import java.time.Duration;
 import java.util.concurrent.TimeUnit;
 
+import javax.annotation.Nonnull;
+
 import org.opensaml.core.criterion.EntityIdCriterion;
 import org.opensaml.core.testing.XMLObjectBaseTestCase;
 import org.opensaml.core.xml.XMLObject;
@@ -109,7 +111,7 @@ public class LocalDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
 
     @Test
     public void testBasicResolveLifecycle() throws ResolverException, IOException {
-        sourceManager.save(sha1Digester.apply(entityID1), entity1);
+        sourceManager.save(sha1Digester(entityID1), entity1);
         
         Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(entityID1))), entity1);
         
@@ -117,7 +119,7 @@ public class LocalDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
         Assert.assertNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(entityID2))));
         
         // Add it
-        sourceManager.save(sha1Digester.apply(entityID2), entity2);
+        sourceManager.save(sha1Digester(entityID2), entity2);
         
         // Wait for the negative lookup cache to expire
         Uninterruptibles.sleepUninterruptibly(resolver.getNegativeLookupCacheDuration().toMillis()+150, TimeUnit.MILLISECONDS);
@@ -126,10 +128,10 @@ public class LocalDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
         Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(entityID2))), entity2);
         
         // Remove source data
-        sourceManager.remove(sha1Digester.apply(entityID1));
-        sourceManager.remove(sha1Digester.apply(entityID2));
-        Assert.assertNull(sourceManager.load(sha1Digester.apply(entityID1)));
-        Assert.assertNull(sourceManager.load(sha1Digester.apply(entityID2)));
+        sourceManager.remove(sha1Digester(entityID1));
+        sourceManager.remove(sha1Digester(entityID2));
+        Assert.assertNull(sourceManager.load(sha1Digester(entityID1)));
+        Assert.assertNull(sourceManager.load(sha1Digester(entityID2)));
         
         // Should still be live b/c already resolved
         Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(entityID1))), entity1);
@@ -144,7 +146,7 @@ public class LocalDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
         resolver.setParserPool(parserPool);
         resolver.initialize();
         
-        sourceManager.save(sha1Digester.apply(entityID1), entity1);
+        sourceManager.save(sha1Digester(entityID1), entity1);
         
         // This will resolve from source manager directly
         Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(entityID1))), entity1);
@@ -179,4 +181,12 @@ public class LocalDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
         Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(entityID1))), entity1);
     }
     
+    @Nonnull private String sha1Digester(@Nonnull final String input) {
+        final String sha1 = sha1Digester.apply(input);
+        if (sha1 == null) {
+            throw new IllegalStateException("Digest was null");
+        }
+        return sha1;
+    }
+    
 }
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list