Merge "b/163430475 Refactor traverse methods to return extensions"
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidator.java
index 32a24a9..18400b8 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidator.java
@@ -1,11 +1,14 @@
 package com.apigee.security.oas.extendedvalidator;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.flogger.FluentLogger;
 import javax.inject.Inject;
 import org.openapi4j.parser.model.v3.OpenApi3;
 
 final class BaseExtendedValidator implements ExtendedValidator {
 
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
   private final TraversalHelperFactory traversalHelperFactory;
 
   @Inject
@@ -17,5 +20,9 @@
   public void validate(OpenApi3 openApiSpec) {
     TraversalHelper traversalHelper = traversalHelperFactory.create(ImmutableList.of());
     traversalHelper.sendOpenApiTraversal(openApiSpec);
+    ImmutableSet<Extension> extensions = traversalHelper.traverse();
+
+    // TODO(b/161441872) : Add extension validation logic
+    logger.atInfo().log("%s", extensions);
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionValidationIntegrator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionValidationIntegrator.java
index 055b696..1fc861e 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionValidationIntegrator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionValidationIntegrator.java
@@ -1,13 +1,20 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import java.util.Optional;
+import org.openapi4j.parser.model.OpenApiSchema;
 
 final class BaseExtensionValidationIntegrator extends ExtensionValidationIntegrator {
 
   // TODO(b/161441872): Inject ExtensionValidationIntegrator member dependencies.
 
   @Override
-  public void validateExtensions(ImmutableMap<String, Object> extensions) {
+  public void validateExtensions(
+      ImmutableMap<String, Object> extensions,
+      ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
+          updatedTraversalPath) {
     // TODO(b/161441872): Add validation logic here.
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinator.java
index b08fc02..b2b2769 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinator.java
@@ -1,6 +1,8 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import com.google.common.collect.ImmutableSet;
 import java.util.ArrayDeque;
+import java.util.Optional;
 
 /** Executes {@linkplain Traversal TraversalCommands} in a depth first (right to left) fashion. */
 final class BaseTraversalCoordinator implements TraversalCoordinator {
@@ -8,10 +10,15 @@
   private final ArrayDeque<TraversalCommand> stack = new ArrayDeque<>();
 
   @Override
-  public void traverse() {
+  public ImmutableSet<Extension> traverse() {
+    ImmutableSet.Builder<Extension> setBuilder = new ImmutableSet.Builder<>();
+
     while (!stack.isEmpty()) {
-      stack.pop().traverse();
+      Optional.ofNullable(stack.pop().traverse())
+          .ifPresent(extensions -> setBuilder.addAll(extensions));
     }
+
+    return setBuilder.build();
   }
 
   @Override
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalHelper.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalHelper.java
index 58e4e14..f160c01 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalHelper.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalHelper.java
@@ -2,6 +2,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -47,6 +48,11 @@
   }
 
   @Override
+  public ImmutableSet<Extension> traverse() {
+    return coordinator.traverse();
+  }
+
+  @Override
   public void sendCallbackTraversals(ImmutableMap<String, Callback> callbackMap) {
     Optional.ofNullable(callbackMap)
         .ifPresent(
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/CallbackTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/CallbackTraversal.java
index 7ed41fc..c00db58 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/CallbackTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/CallbackTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -13,26 +16,25 @@
   @Inject
   CallbackTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted Callback openApiSchemaObj,
       @Assisted String name) {
-    super(
-        traversalHelperFactory,
-        extensionValidationIntegrator,
-        traversalPath,
-        openApiSchemaObj,
-        name);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj, name);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
+        updatedTraversalPath = getUpdatedTraversalPath();
 
-    TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath());
+    TraversalHelper traversalHelper = traversalHelperFactory.create(updatedTraversalPath);
 
     traversalHelper.sendPathTraversals(
         Immutables.toImmutableMap(openApiSchemaObj.getCallbackPaths()));
+
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), updatedTraversalPath);
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversal.java
index 9c6691f..3c07fb6 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -14,15 +17,16 @@
   @Inject
   ContactTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted Contact openApiSchemaObj) {
-    super(traversalHelperFactory, extensionValidationIntegrator, traversalPath, openApiSchemaObj);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), getUpdatedTraversalPath());
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorModule.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorModule.java
index f7b0dc0..8237d03 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorModule.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorModule.java
@@ -2,6 +2,7 @@
 
 import com.google.inject.AbstractModule;
 import com.google.inject.assistedinject.FactoryModuleBuilder;
+import javax.inject.Singleton;
 
 /**
  * Configures the bindings of inner components to be installed in the {@link
@@ -15,7 +16,7 @@
 
     bind(ExtensionValidationIntegrator.class).to(BaseExtensionValidationIntegrator.class);
 
-    bind(TraversalCoordinator.class).to(BaseTraversalCoordinator.class);
+    bind(TraversalCoordinator.class).to(BaseTraversalCoordinator.class).in(Singleton.class);
 
     install(
         new FactoryModuleBuilder()
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidationIntegrator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidationIntegrator.java
index 26fcaed..c38c062 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidationIntegrator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidationIntegrator.java
@@ -1,6 +1,10 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import java.util.Optional;
+import org.openapi4j.parser.model.OpenApiSchema;
 
 /** Carries out the process of validating ApiSecurityTool's OpenApi extensions. */
 public abstract class ExtensionValidationIntegrator {
@@ -11,5 +15,8 @@
    * Validates extensions from a mapping of extension {@linkplain String name} to extension
    * {@linkplain Object content}.
    */
-  abstract void validateExtensions(ImmutableMap<String, Object> extensions);
+  abstract void validateExtensions(
+      ImmutableMap<String, Object> extensions,
+      ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
+          updatedTraversalPath);
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExternalDocsTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExternalDocsTraversal.java
index 47b08ab..072ac6d 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExternalDocsTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExternalDocsTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -15,16 +18,17 @@
   @Inject
   ExternalDocsTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted ExternalDocs openApiSchemaObj,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
               traversalPath) {
-    super(traversalHelperFactory, extensionValidationIntegrator, traversalPath, openApiSchemaObj);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), getUpdatedTraversalPath());
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversal.java
index 5d89df2..d1df744 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -14,20 +17,24 @@
   @Inject
   InfoTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted Info openApiSchemaObj) {
-    super(traversalHelperFactory, extensionValidationIntegrator, traversalPath, openApiSchemaObj);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
+        updatedTraversalPath = getUpdatedTraversalPath();
 
-    TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath());
+    TraversalHelper traversalHelper = traversalHelperFactory.create(updatedTraversalPath);
 
     traversalHelper.sendContactTraversal(openApiSchemaObj.getContact());
     traversalHelper.sendLicenseTraversal(openApiSchemaObj.getLicense());
+
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), updatedTraversalPath);
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversal.java
index e3b20f0..2e6116f 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -14,15 +17,16 @@
   @Inject
   LicenseTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted License openApiSchemaObj) {
-    super(traversalHelperFactory, extensionValidationIntegrator, traversalPath, openApiSchemaObj);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), getUpdatedTraversalPath());
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java
index df3a15a..c2ff58f 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java
@@ -4,8 +4,12 @@
 import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
+import java.util.Map;
+import java.util.Optional;
 import javax.inject.Inject;
+import org.openapi4j.parser.model.OpenApiSchema;
 import org.openapi4j.parser.model.v3.OpenApi3;
 
 /** A {@link Traversal} that traverses an {@link OpenApi3} object. */
@@ -15,16 +19,17 @@
   @Inject
   OpenApiSpecificationTraversal(
       TraversalHelperFactory factory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted OpenApi3 openApiSchemaObj) {
-    super(factory, extensionValidationIntegrator, ImmutableList.of(), openApiSchemaObj);
+    super(factory, extensionFactory, ImmutableList.of(), openApiSchemaObj);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
+        updatedTraversalPath = getUpdatedTraversalPath();
 
-    TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath());
+    TraversalHelper traversalHelper = traversalHelperFactory.create(updatedTraversalPath);
 
     traversalHelper.sendExternalDocsTraversal(openApiSchemaObj.getExternalDocs());
     traversalHelper.sendInfoTraversal(openApiSchemaObj.getInfo());
@@ -34,5 +39,8 @@
     traversalHelper.sendSecurityRequirementTraversals(
         toImmutableList(openApiSchemaObj.getSecurityRequirements()));
     // TODO(b/162677159): Send Components traversal.
+
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), updatedTraversalPath);
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OperationTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OperationTraversal.java
index 22ed41d..4d89636 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OperationTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OperationTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -14,24 +17,20 @@
   @Inject
   OperationTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted Operation openApiSchemaObj,
       @Assisted String name) {
-    super(
-        traversalHelperFactory,
-        extensionValidationIntegrator,
-        traversalPath,
-        openApiSchemaObj,
-        name);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj, name);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
+        updatedTraversalPath = getUpdatedTraversalPath();
 
-    TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath());
+    TraversalHelper traversalHelper = traversalHelperFactory.create(updatedTraversalPath);
 
     traversalHelper.sendExternalDocsTraversal(openApiSchemaObj.getExternalDocs());
     traversalHelper.sendCallbackTraversals(
@@ -43,5 +42,8 @@
         Immutables.toImmutableMap(openApiSchemaObj.getResponses()));
     traversalHelper.sendSecurityRequirementTraversals(
         Immutables.toImmutableList(openApiSchemaObj.getSecurityRequirements()));
+
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), updatedTraversalPath);
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ParameterTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ParameterTraversal.java
index 869fcb7..02f9f28 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ParameterTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ParameterTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -13,18 +16,20 @@
   @Inject
   ParameterTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted Parameter openApiSchemaObj) {
-    super(traversalHelperFactory, extensionValidationIntegrator, traversalPath, openApiSchemaObj);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
 
     // TODO(b/162897637): Send MediaType Traversal
     // TODO(b/162942899): Send Example Traversal
+
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), getUpdatedTraversalPath());
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversal.java
index 5ba0797..e6da1ce 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -14,29 +17,28 @@
   @Inject
   PathTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted Path openApiSchemaObj,
       @Assisted String name) {
-    super(
-        traversalHelperFactory,
-        extensionValidationIntegrator,
-        traversalPath,
-        openApiSchemaObj,
-        name);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj, name);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
+        updatedTraversalPath = getUpdatedTraversalPath();
 
-    TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath());
+    TraversalHelper traversalHelper = traversalHelperFactory.create(updatedTraversalPath);
 
     traversalHelper.sendParameterTraversals(
         Immutables.toImmutableList(openApiSchemaObj.getParameters()));
     traversalHelper.sendServerTraversals(Immutables.toImmutableList(openApiSchemaObj.getServers()));
     traversalHelper.sendOperationTraversals(
         Immutables.toImmutableMap(openApiSchemaObj.getOperations()));
+
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), updatedTraversalPath);
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ResponseTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ResponseTraversal.java
index d214ada..17370b6 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ResponseTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ResponseTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -14,23 +17,20 @@
   @Inject
   ResponseTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted Response openApiSchemaObj,
       @Assisted String name) {
-    super(
-        traversalHelperFactory,
-        extensionValidationIntegrator,
-        traversalPath,
-        openApiSchemaObj,
-        name);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj, name);
   }
 
   @Override
-  public void traverse() {
+  public ImmutableSet<Extension> traverse() {
     // TODO(b/162897637): Send MediaType Traversals.
     // TODO(b/162949105): Send Header Traversals.
     // TODO(b/162949106): Send Link Traversals.
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), getUpdatedTraversalPath());
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/SecurityRequirementTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/SecurityRequirementTraversal.java
index 78f614e..ce8f0cd 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/SecurityRequirementTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/SecurityRequirementTraversal.java
@@ -1,6 +1,7 @@
 package com.apigee.security.oas.extendedvalidator;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -14,15 +15,16 @@
   @Inject
   SecurityRequirementTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted SecurityRequirement openApiSchemaObj) {
-    super(traversalHelperFactory, extensionValidationIntegrator, traversalPath, openApiSchemaObj);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    // SecurityRequirement object cannot have extensions.
+    return ImmutableSet.of();
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversal.java
index c464d7a..160ee27 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversal.java
@@ -3,6 +3,7 @@
 import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -16,19 +17,23 @@
   @Inject
   ServerTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted Server openApiSchemaObj) {
-    super(traversalHelperFactory, extensionValidationIntegrator, traversalPath, openApiSchemaObj);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
+        updatedTraversalPath = getUpdatedTraversalPath();
 
-    TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath());
+    TraversalHelper traversalHelper = traversalHelperFactory.create(updatedTraversalPath);
 
     traversalHelper.sendServerVariableTraversals(toImmutableMap(openApiSchemaObj.getVariables()));
+
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), updatedTraversalPath);
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversal.java
index d1284ef..ddb7e27 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -15,21 +18,17 @@
   @Inject
   ServerVariableTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted ServerVariable openApiSchemaObj,
       @Assisted String name) {
-    super(
-        traversalHelperFactory,
-        extensionValidationIntegrator,
-        traversalPath,
-        openApiSchemaObj,
-        name);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj, name);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), getUpdatedTraversalPath());
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TagTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TagTraversal.java
index c6e9a40..5a21d2c 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TagTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TagTraversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap;
+
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.assistedinject.Assisted;
 import java.util.Map;
 import java.util.Optional;
@@ -14,19 +17,23 @@
   @Inject
   TagTraversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       @Assisted
           ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       @Assisted Tag openApiSchemaObj) {
-    super(traversalHelperFactory, extensionValidationIntegrator, traversalPath, openApiSchemaObj);
+    super(traversalHelperFactory, extensionFactory, traversalPath, openApiSchemaObj);
   }
 
   @Override
-  public void traverse() {
-    // TODO(b/161441872): Process extensions.
+  public ImmutableSet<Extension> traverse() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
+        updatedTraversalPath = getUpdatedTraversalPath();
 
-    TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath());
+    TraversalHelper traversalHelper = traversalHelperFactory.create(updatedTraversalPath);
 
     traversalHelper.sendExternalDocsTraversal(openApiSchemaObj.getExternalDocs());
+
+    return generateExtensions(
+        toImmutableMap(openApiSchemaObj.getExtensions()), updatedTraversalPath);
   }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Traversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Traversal.java
index 37ebd51..0c3986f 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Traversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Traversal.java
@@ -1,6 +1,9 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import java.util.AbstractMap;
 import java.util.ArrayDeque;
 import java.util.Map;
@@ -11,19 +14,20 @@
 abstract class Traversal<T extends OpenApiSchema> {
 
   protected final T openApiSchemaObj;
-  protected final ExtensionValidationIntegrator extensionValidationIntegrator;
+  protected final ExtensionFactory extensionFactory;
   protected final TraversalHelperFactory traversalHelperFactory;
   private final ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
       traversalPath;
   private final Optional<String> name;
+  private final ObjectMapper objectMapper = new ObjectMapper();
 
   Traversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       T openApiSchemaObj) {
     this.traversalHelperFactory = traversalHelperFactory;
-    this.extensionValidationIntegrator = extensionValidationIntegrator;
+    this.extensionFactory = extensionFactory;
     this.traversalPath = traversalPath;
     this.openApiSchemaObj = openApiSchemaObj;
     this.name = Optional.empty();
@@ -31,12 +35,12 @@
 
   Traversal(
       TraversalHelperFactory traversalHelperFactory,
-      ExtensionValidationIntegrator extensionValidationIntegrator,
+      ExtensionFactory extensionFactory,
       ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
       T openApiSchemaObj,
       String name) {
     this.traversalHelperFactory = traversalHelperFactory;
-    this.extensionValidationIntegrator = extensionValidationIntegrator;
+    this.extensionFactory = extensionFactory;
     this.traversalPath = traversalPath;
     this.openApiSchemaObj = openApiSchemaObj;
     this.name = Optional.of(name);
@@ -50,4 +54,20 @@
         new AbstractMap.SimpleImmutableEntry<>(openApiSchemaObj.getClass(), name));
     return ImmutableList.copyOf(updatedTraversalPath);
   }
+
+  protected ImmutableSet<Extension> generateExtensions(
+      ImmutableMap<String, Object> extensions,
+      ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath) {
+    ImmutableSet.Builder<Extension> setBuilder = new ImmutableSet.Builder<>();
+
+    Optional.ofNullable(extensions)
+        .orElse(ImmutableMap.of())
+        .forEach(
+            (name, content) ->
+                setBuilder.add(
+                    extensionFactory.create(
+                        name, objectMapper.valueToTree(content), traversalPath)));
+
+    return setBuilder.build();
+  }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommand.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommand.java
index 257eb80..a2f5d9a 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommand.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommand.java
@@ -1,8 +1,10 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import com.google.common.collect.ImmutableSet;
+
 /** Used in conjunction with {@link Traversal} to traverse an OpenApi4j object. */
 public interface TraversalCommand {
 
-  /** Starts traversal logic. */
-  void traverse();
+  /** Starts traversal logic and collects {@link Extension extensions}. */
+  ImmutableSet<Extension> traverse();
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCoordinator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCoordinator.java
index bb15592..0aa8568 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCoordinator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCoordinator.java
@@ -1,13 +1,18 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import com.google.common.collect.ImmutableSet;
+
 /**
  * A {@link TraversalCoordinator} serves as the coordinator for otherwise interdependent {@linkplain
  * TraversalCommand TraversalCommands}.
  */
 public interface TraversalCoordinator {
 
-  /** Traverses handled {@linkplain Traversal TraversalCommands}. */
-  void traverse();
+  /**
+   * Traverses handled {@linkplain Traversal TraversalCommands} and returns {@link Extension
+   * extensions} found.
+   */
+  ImmutableSet<Extension> traverse();
 
   /**
    * Handles given {@link Traversal} in accordance with {@linkplain TraversalCoordinator
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalHelper.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalHelper.java
index 1f6ea32..680b896 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalHelper.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalHelper.java
@@ -2,6 +2,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import org.openapi4j.parser.model.v3.Callback;
 import org.openapi4j.parser.model.v3.Contact;
 import org.openapi4j.parser.model.v3.ExternalDocs;
@@ -47,4 +48,6 @@
   void sendServerVariableTraversals(ImmutableMap<String, ServerVariable> serverVariables);
 
   void sendTagTraversals(ImmutableList<Tag> tagList);
+
+  ImmutableSet<Extension> traverse();
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/CallbackTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/CallbackTraversalTest.java
index dc4944d..1acb831 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/CallbackTraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/CallbackTraversalTest.java
@@ -1,12 +1,16 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.util.Map;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -28,21 +32,18 @@
   private CallbackTraversal callbackTraversal;
 
   @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+  @Mock private ExtensionFactory extensionFactory;
   @Mock private TraversalHelperFactory traversalHelperFactory;
   @Mock private TraversalHelper traversalHelper;
-  @Mock private ExtensionValidationIntegrator extensionValidationIntegrator;
   @Mock private Callback callback;
+  @Mock private Extension extension;
 
   /** Sets up live and mocked instances for testing. */
   @Before
   public void setup() {
     callbackTraversal =
         new CallbackTraversal(
-            traversalHelperFactory,
-            extensionValidationIntegrator,
-            ImmutableList.of(),
-            callback,
-            "name");
+            traversalHelperFactory, extensionFactory, ImmutableList.of(), callback, "name");
 
     when(callback.getCallbackPaths()).thenReturn(callbackPaths);
 
@@ -64,4 +65,20 @@
 
     verify(traversalHelper, atLeastOnce()).sendPathTraversals(any());
   }
+
+  @Test
+  public void traverse_withExtensions_returnsGeneratedExtensions() {
+    when(callback.getExtensions()).thenReturn(Map.of("x-callback", ""));
+    when(extensionFactory.create(anyString(), any(JsonNode.class), any(ImmutableList.class)))
+        .thenReturn(extension);
+
+    assertThat(callbackTraversal.traverse()).hasSize(1).containsOnlyOnce(extension);
+  }
+
+  @Test
+  public void traverse_withoutExtensions_returnsEmptyExtensionsImmutableList() {
+    when(callback.getExtensions()).thenReturn(Map.of());
+
+    assertThat(callbackTraversal.traverse()).isEmpty();
+  }
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/InfoTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/InfoTraversalTest.java
index 462db49..17b5e8c 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/InfoTraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/InfoTraversalTest.java
@@ -1,10 +1,14 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.ImmutableList;
+import java.util.Map;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -25,7 +29,8 @@
 
   @Mock private TraversalHelperFactory traversalHelperFactory;
   @Mock private TraversalHelper traversalHelper;
-  @Mock private ExtensionValidationIntegrator extensionValidationIntegrator;
+  @Mock private ExtensionFactory extensionFactory;
+  @Mock private Extension extension;
   @Mock private Info info;
 
   private final License license = new License();
@@ -37,8 +42,7 @@
   @Before
   public void setup() {
     infoTraversal =
-        new InfoTraversal(
-            traversalHelperFactory, extensionValidationIntegrator, ImmutableList.of(), info);
+        new InfoTraversal(traversalHelperFactory, extensionFactory, ImmutableList.of(), info);
 
     when(info.getContact()).thenReturn(contact);
     when(info.getLicense()).thenReturn(license);
@@ -59,4 +63,20 @@
 
     verify(traversalHelper).sendLicenseTraversal(license);
   }
+
+  @Test
+  public void traverse_withExtensions_returnsGeneratedExtensions() {
+    when(info.getExtensions()).thenReturn(Map.of("x-info", ""));
+    when(extensionFactory.create(anyString(), any(JsonNode.class), any(ImmutableList.class)))
+        .thenReturn(extension);
+
+    assertThat(infoTraversal.traverse()).hasSize(1).containsOnlyOnce(extension);
+  }
+
+  @Test
+  public void traverse_withoutExtensions_returnsEmptyExtensionsImmutableList() {
+    when(info.getExtensions()).thenReturn(Map.of());
+
+    assertThat(infoTraversal.traverse()).isEmpty();
+  }
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java
index 1620e6a..f1375a0 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java
@@ -1,12 +1,16 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.util.Map;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -31,8 +35,9 @@
 
   @Mock private TraversalHelperFactory traversalHelperFactory;
   @Mock private TraversalHelper traversalHelper;
-  @Mock private ExtensionValidationIntegrator extensionValidationIntegrator;
+  @Mock private ExtensionFactory extensionFactory;
   @Mock private OpenApi3 openApiSpec;
+  @Mock private Extension extension;
 
   private final Info info = new Info();
   private final ExternalDocs externalDocs = new ExternalDocs();
@@ -53,8 +58,7 @@
   @Before
   public void setup() {
     openApiSpecificationTraversal =
-        new OpenApiSpecificationTraversal(
-            traversalHelperFactory, extensionValidationIntegrator, openApiSpec);
+        new OpenApiSpecificationTraversal(traversalHelperFactory, extensionFactory, openApiSpec);
 
     when(openApiSpec.getServers()).thenReturn(servers);
     when(openApiSpec.getTags()).thenReturn(tags);
@@ -143,4 +147,20 @@
 
     verify(traversalHelper, atLeastOnce()).sendTagTraversals(any());
   }
+
+  @Test
+  public void traverse_withExtensions_returnsGeneratedExtensions() {
+    when(openApiSpec.getExtensions()).thenReturn(Map.of("x-openapi", ""));
+    when(extensionFactory.create(anyString(), any(JsonNode.class), any(ImmutableList.class)))
+        .thenReturn(extension);
+
+    assertThat(openApiSpecificationTraversal.traverse()).hasSize(1).containsOnlyOnce(extension);
+  }
+
+  @Test
+  public void traverse_withoutExtensions_returnsEmptyExtensionsImmutableList() {
+    when(openApiSpec.getExtensions()).thenReturn(Map.of());
+
+    assertThat(openApiSpecificationTraversal.traverse()).isEmpty();
+  }
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OperationTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OperationTraversalTest.java
index 5e4436e..1bd3800 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OperationTraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OperationTraversalTest.java
@@ -1,12 +1,16 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.util.Map;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -31,7 +35,8 @@
 
   @Mock private TraversalHelperFactory traversalHelperFactory;
   @Mock private TraversalHelper traversalHelper;
-  @Mock private ExtensionValidationIntegrator extensionValidationIntegrator;
+  @Mock private ExtensionFactory extensionFactory;
+  @Mock private Extension extension;
   @Mock private Operation operation;
 
   private final ExternalDocs externalDocs = new ExternalDocs();
@@ -53,7 +58,6 @@
   /** Sets up live and mocked instances for testing. */
   @Before
   public void setup() {
-
     when(operation.getExternalDocs()).thenReturn(externalDocs);
     when(operation.getServers()).thenReturn(servers);
     when(operation.getParameters()).thenReturn(parameters);
@@ -63,11 +67,7 @@
 
     operationTraversal =
         new OperationTraversal(
-            traversalHelperFactory,
-            extensionValidationIntegrator,
-            ImmutableList.of(),
-            operation,
-            "name");
+            traversalHelperFactory, extensionFactory, ImmutableList.of(), operation, "name");
 
     when(traversalHelperFactory.create(any(ImmutableList.class))).thenReturn(traversalHelper);
   }
@@ -158,4 +158,20 @@
 
     verify(traversalHelper, atLeastOnce()).sendServerTraversals(any());
   }
+
+  @Test
+  public void traverse_withExtensions_returnsGeneratedExtensions() {
+    when(operation.getExtensions()).thenReturn(Map.of("x-operation", ""));
+    when(extensionFactory.create(anyString(), any(JsonNode.class), any(ImmutableList.class)))
+        .thenReturn(extension);
+
+    assertThat(operationTraversal.traverse()).hasSize(1).containsOnlyOnce(extension);
+  }
+
+  @Test
+  public void traverse_withoutExtensions_returnsEmptyExtensionsImmutableList() {
+    when(operation.getExtensions()).thenReturn(Map.of());
+
+    assertThat(operationTraversal.traverse()).isEmpty();
+  }
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/PathTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/PathTraversalTest.java
index 042f0a4..3bc0518 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/PathTraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/PathTraversalTest.java
@@ -1,12 +1,16 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.util.Map;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -37,7 +41,8 @@
   @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
   @Mock private TraversalHelperFactory traversalHelperFactory;
   @Mock private TraversalHelper traversalHelper;
-  @Mock private ExtensionValidationIntegrator extensionValidationIntegrator;
+  @Mock private ExtensionFactory extensionFactory;
+  @Mock private Extension extension;
   @Mock private Path path;
 
   /** Sets up live and mocked instances for testing. */
@@ -45,11 +50,7 @@
   public void setup() {
     pathTraversal =
         new PathTraversal(
-            traversalHelperFactory,
-            extensionValidationIntegrator,
-            ImmutableList.of(),
-            path,
-            "name");
+            traversalHelperFactory, extensionFactory, ImmutableList.of(), path, "name");
 
     when(path.getOperations()).thenReturn(operations);
     when(path.getParameters()).thenReturn(parameters);
@@ -105,4 +106,20 @@
 
     verify(traversalHelper, atLeastOnce()).sendServerTraversals(any());
   }
+
+  @Test
+  public void traverse_withExtensions_returnsGeneratedExtensions() {
+    when(path.getExtensions()).thenReturn(Map.of("x-path", ""));
+    when(extensionFactory.create(anyString(), any(JsonNode.class), any(ImmutableList.class)))
+        .thenReturn(extension);
+
+    assertThat(pathTraversal.traverse()).hasSize(1).containsOnlyOnce(extension);
+  }
+
+  @Test
+  public void traverse_withoutExtensions_returnsEmptyExtensionsImmutableList() {
+    when(path.getExtensions()).thenReturn(Map.of());
+
+    assertThat(pathTraversal.traverse()).isEmpty();
+  }
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ServerTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ServerTraversalTest.java
index 5887005..b77c054 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ServerTraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ServerTraversalTest.java
@@ -1,12 +1,16 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.util.Map;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -26,7 +30,8 @@
 
   @Mock private TraversalHelperFactory traversalHelperFactory;
   @Mock private TraversalHelper traversalHelper;
-  @Mock private ExtensionValidationIntegrator extensionValidationIntegrator;
+  @Mock private ExtensionFactory extensionFactory;
+  @Mock private Extension extension;
   @Mock private Server server;
   @Mock private ServerVariable serverVariable;
 
@@ -37,8 +42,7 @@
   @Before
   public void setup() {
     serverTraversal =
-        new ServerTraversal(
-            traversalHelperFactory, extensionValidationIntegrator, ImmutableList.of(), server);
+        new ServerTraversal(traversalHelperFactory, extensionFactory, ImmutableList.of(), server);
 
     serverVariables =
         ImmutableMap.of(
@@ -66,4 +70,20 @@
 
     verify(traversalHelper, atLeastOnce()).sendServerVariableTraversals(any());
   }
+
+  @Test
+  public void traverse_withExtensions_returnsGeneratedExtensions() {
+    when(server.getExtensions()).thenReturn(Map.of("x-server", ""));
+    when(extensionFactory.create(anyString(), any(JsonNode.class), any(ImmutableList.class)))
+        .thenReturn(extension);
+
+    assertThat(serverTraversal.traverse()).hasSize(1).containsOnlyOnce(extension);
+  }
+
+  @Test
+  public void traverse_withoutExtensions_returnsEmptyExtensionsImmutableList() {
+    when(server.getExtensions()).thenReturn(Map.of());
+
+    assertThat(serverTraversal.traverse()).isEmpty();
+  }
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TagTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TagTraversalTest.java
index ab86592..54ec074 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TagTraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TagTraversalTest.java
@@ -1,10 +1,14 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.ImmutableList;
+import java.util.Map;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -24,7 +28,8 @@
 
   @Mock private TraversalHelperFactory traversalHelperFactory;
   @Mock private TraversalHelper traversalHelper;
-  @Mock private ExtensionValidationIntegrator extensionValidationIntegrator;
+  @Mock private ExtensionFactory extensionFactory;
+  @Mock private Extension extension;
   @Mock private Tag tag;
 
   private final ExternalDocs externalDocs = new ExternalDocs();
@@ -35,8 +40,7 @@
   @Before
   public void setup() {
     tagTraversal =
-        new TagTraversal(
-            traversalHelperFactory, extensionValidationIntegrator, ImmutableList.of(), tag);
+        new TagTraversal(traversalHelperFactory, extensionFactory, ImmutableList.of(), tag);
 
     when(tag.getExternalDocs()).thenReturn(externalDocs);
     when(traversalHelperFactory.create(any(ImmutableList.class))).thenReturn(traversalHelper);
@@ -48,4 +52,20 @@
 
     verify(traversalHelper).sendExternalDocsTraversal(externalDocs);
   }
+
+  @Test
+  public void traverse_withExtensions_returnsGeneratedExtensions() {
+    when(tag.getExtensions()).thenReturn(Map.of("x-tag", ""));
+    when(extensionFactory.create(anyString(), any(JsonNode.class), any(ImmutableList.class)))
+        .thenReturn(extension);
+
+    assertThat(tagTraversal.traverse()).hasSize(1).containsOnlyOnce(extension);
+  }
+
+  @Test
+  public void traverse_withoutExtensions_returnsEmptyExtensionsImmutableList() {
+    when(tag.getExtensions()).thenReturn(Map.of());
+
+    assertThat(tagTraversal.traverse()).isEmpty();
+  }
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalTest.java
index e99a7d3..9df32b5 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalTest.java
@@ -23,7 +23,7 @@
   @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
 
   @Mock private TraversalHelperFactory traversalHelperFactory;
-  @Mock private ExtensionValidationIntegrator baseExtensionValidationIntegrator;
+  @Mock private ExtensionFactory extensionFactory;
 
   @Test
   public void instantiate_traversal_addsTraversalsOpenApiObjClassToTraversalPath() {
@@ -31,11 +31,7 @@
     ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> prevTraversalPath =
         ImmutableList.copyOf(new ArrayDeque<>());
     InfoTraversal traversal =
-        new InfoTraversal(
-            traversalHelperFactory,
-            baseExtensionValidationIntegrator,
-            prevTraversalPath,
-            new Info());
+        new InfoTraversal(traversalHelperFactory, extensionFactory, prevTraversalPath, new Info());
 
     ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
         updatedTraversalPath = traversal.getUpdatedTraversalPath();