Repository: eclipse/microprofile-open-api
Pull request #287 (2018-10-13 08:28:30)

Remove 'extends Map<?,?>' from model classes 
* merge `master` into `2.0`
* remove `extends Map<..,..>` from  following model classes :
  * Paths
  * Callback
  * Content
  * APIResponses
  * Scopes
  * SecurityRequirement
  * ServerVariables

See Issue #248, follow up of #283 for the `2.0` branch


Patch:
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/Paths.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/Paths.java
index 66ee5d0..552d24d 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/Paths.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/Paths.java
@@ -29,7 +29,7 @@ import java.util.Map;
  * 
  * @see <a href= "https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathsObject"> OpenAPI Specification Paths Object</a>
  */
-public interface Paths extends Constructible, Extensible<Paths>, Map<String, PathItem> {
+public interface Paths extends Constructible, Extensible<Paths> {
 
     /**
      * Adds the given path item to this Paths and return this instance of Paths
@@ -40,14 +40,6 @@ public interface Paths extends Constructible, Extensible<Paths>, Map<String, Pat
      */
     Paths addPathItem(String name, PathItem item);
 
-    /**
-     * Adds all the path items to this Paths and return this instance of Paths
-     * 
-     * @param items a map containing the list of paths. Keys MUST begin with a slash.
-     * @return the current Paths instance
-     */
-    Paths addPathItems(Map<String, PathItem> items);
-
     /**
      * Removes the given path item to this Paths.
      * 
@@ -56,19 +48,32 @@ public interface Paths extends Constructible, Extensible<Paths>, Map<String, Pat
     void removePathItem(String name);
 
     /**
-     * Returns an immutable map of the path items.
+     * Returns a copy map (potentially immutable) of the path items.
      * 
      * @return all items
      */
     Map<String, PathItem> getPathItems();
 
     /**
-     * Check whether a path item is present to the map. This is a convenience method for <code>getPathItems().containsKey(name)</code>
+     * Set the path items map to this Paths
+     * 
+     * @param items a map containing the list of paths. Keys MUST begin with a slash.
+     */
+    void setPathItems(Map<String, PathItem> items);
+
+    /**
+     * Check whether a path item is present in the map. This is a convenience method for <code>getPathItems().containsKey(name)</code>
      * 
      * @param name a path name in the format valid for a Paths object.
      * @return a boolean to indicate if the path item is present or not.
      */
-    boolean hasPathItem(String name);
+    default boolean hasPathItem(String name) {
+        Map<String, PathItem> map = getPathItems();
+        if (map == null) {
+            return false;
+        }
+        return map.containsKey(name);
+    }
 
     /**
      * Returns a path item for a given name. This is a convenience method for <code>getPathItems().get(name)</code>
@@ -76,51 +81,12 @@ public interface Paths extends Constructible, Extensible<Paths>, Map<String, Pat
      * @param name a path name in the format valid for a Paths object.
      * @return the corresponding path item or null.
      */
-    PathItem getPathItem(String name);
-
-    /**
-     * In the next version, {@link Paths} will no longer extends {@link Map}, this method will no longer be present.
-     * Use {@link #getPathItem(String)} instead.
-     * @deprecated since 1.1
-     */
-    @Deprecated
-    @Override
-    PathItem get(Object key);
-
-    /**
-     * In the next version, {@link Paths} will no longer extends {@link Map}, this method will no longer be present.
-     * Use {@link #hasPathItem(String)} instead.
-     * @deprecated since 1.1
-     */
-    @Deprecated
-    @Override
-    boolean containsKey(Object key);
-    
-    /**
-     * In the next version, {@link Paths} will no longer extends {@link Map}, this method will no longer be present.
-     * Use {@link #addPathItem(String, PathItem)} instead.
-     * @deprecated since 1.1
-     */
-    @Deprecated
-    @Override
-    PathItem put(String key, PathItem value);
-
-    /**
-     * In the next version, {@link Paths} will no longer extends {@link Map}, this method will no longer be present.
-     * Use {@link #addPathItems(Map)} instead.
-     * @deprecated since 1.1
-     */
-    @Deprecated
-    @Override
-    void putAll(Map<? extends String, ? extends PathItem> m);
-
-    /**
-     * In the next version, {@link Paths} will no longer extends {@link Map}, this method will no longer be present.
-     * Use {@link #removePathItem(String)} instead.
-     * @deprecated since 1.1
-     */
-    @Deprecated
-    @Override
-    PathItem remove(Object key);
+    default PathItem getPathItem(String name) {
+        Map<String, PathItem> map = getPathItems();
+        if (map == null) {
+            return null;
+        }
+        return map.get(name);
+    }
 
 }
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/callbacks/Callback.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/callbacks/Callback.java
index 0680add..2931fb2 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/callbacks/Callback.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/callbacks/Callback.java
@@ -33,7 +33,7 @@ import org.eclipse.microprofile.openapi.models.Reference;
  * 
  * @see <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#callbackObject">OpenAPI Specification Callback Object</a>
  */
-public interface Callback extends Constructible, Extensible<Callback>, Reference<Callback>, Map<String, PathItem> {
+public interface Callback extends Constructible, Extensible<Callback>, Reference<Callback> {
 
     /**
      * Adds the given PathItem to this Callback's list of PathItems using the string as its key.
@@ -48,4 +48,53 @@ public interface Callback extends Constructible, Extensible<Callback>, Reference
      */
     Callback addPathItem(String name, PathItem pathItem);
 
+    /**
+     * Removes the given path item of the Callback PathItems.
+     * 
+     * @param name a path name that will be removed.
+     */
+    void removePathItem(String name);
+
+    /**
+     * Returns a copy map (potentially immutable) of the path items.
+     * 
+     * @return all items
+     */
+    Map<String, PathItem> getPathItems();
+
+    /**
+     * Set the path items map to this Callback.
+     * 
+     * @param items a map containing the list of paths.
+     */
+    void setPathItems(Map<String, PathItem> items);
+
+    /**
+     * Check whether a path item is present to the map. This is a convenience method for <code>getPathItems().containsKey(name)</code>
+     * 
+     * @param name a path name in the format valid for a Paths object.
+     * @return a boolean to indicate if the path item is present or not.
+     */
+    default boolean hasPathItem(String name) {
+        Map<String, PathItem> map = getPathItems();
+        if (map == null) {
+            return false;
+        }
+        return map.containsKey(name);
+    }
+
+    /**
+     * Returns a path item for a given name. This is a convenience method for <code>getPathItems().get(name)</code>
+     * 
+     * @param name a path name in the format valid for a Paths object.
+     * @return the corresponding path item or null.
+     */
+    default PathItem getPathItem(String name) {
+        Map<String, PathItem> map = getPathItems();
+        if (map == null) {
+            return null;
+        }
+        return map.get(name);
+    }
+
 }
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Content.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Content.java
index cf6f0ac..e20a62c 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Content.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Content.java
@@ -27,7 +27,7 @@ import org.eclipse.microprofile.openapi.models.Constructible;
  * A map to assist describing the media types for an operation's parameter or response.
  * 
  */
-public interface Content extends Constructible, Map<String, MediaType> {
+public interface Content extends Constructible {
 
     /**
      * Adds the MediaType for this Content, where the key is the name of the MediaType and the value is the object that describes the content passed
@@ -39,4 +39,53 @@ public interface Content extends Constructible, Map<String, MediaType> {
      */
     Content addMediaType(String name, MediaType mediaType);
 
+    /**
+     * Removes the given MediaType for this Content by its name.
+     * 
+     * @param name a path name that will be removed.
+     */
+    void removeMediaType(String name);
+
+    /**
+     * Returns a copy map (potentially immutable) of media types.
+     * 
+     * @return all items
+     */
+    Map<String, MediaType> getMediaTypes();
+
+    /**
+     * Set the media types map to this Content
+     * 
+     * @param mediaTypes a map containing the list of media types. Keys are name of a media type e.g. application/json.
+     */
+    void setMediaTypes(Map<String, MediaType> mediaTypes);
+
+    /**
+     * Check whether a media type is present in the map. This is a convenience method for <code>getMediaTypes().containsKey(name)</code>
+     * 
+     * @param name the name of a media type e.g. application/json.
+     * @return a boolean to indicate if the media type is present or not.
+     */
+    default boolean hasMediaType(String name) {
+        Map<String, MediaType> map = getMediaTypes();
+        if (map == null) {
+            return false;
+        }
+        return map.containsKey(name);
+    }
+
+    /**
+     * Returns a media type for a given name. This is a convenience method for <code>getMediaTypes().get(name)</code>
+     * 
+     * @param name the name of a media type e.g. application/json.
+     * @return the corresponding media type or null.
+     */
+    default MediaType getMediaType(String name) {
+        Map<String, MediaType> map = getMediaTypes();
+        if (map == null) {
+            return null;
+        }
+        return map.get(name);
+    }
+
 }
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/responses/APIResponses.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/responses/APIResponses.java
index 50665eb..4cdc017 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/responses/APIResponses.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/responses/APIResponses.java
@@ -28,23 +28,73 @@ import org.eclipse.microprofile.openapi.models.Extensible;
  *
  * @see <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responses-object">Responses Object</a>
  */
-public interface APIResponses extends Constructible, Extensible<APIResponses>, Map<String, APIResponse> {
+public interface APIResponses extends Constructible, Extensible<APIResponses> {
 
     public static final String DEFAULT = "default";
 
     /**
      * Adds an APIResponse in the format of the name as a key and the item as the value to APIResponses map
      * 
-     * @param name the name of APIResponse 
+     * @param name the name of APIResponse (http status code eventually with wildcard or {@value #DEFAULT})
      * @param apiResponse the APIResponse object to be added to APIResponses map
      * @return APIResponses map with the added ApiResponse instance
      **/
     APIResponses addAPIResponse(String name, APIResponse apiResponse);
 
+
+    /**
+     * Removes the given APIResponse to this APIResponses.
+     * 
+     * @param name the name of APIResponse that will be removed (http status code eventually with wildcard or {@value #DEFAULT})
+     */
+    void removeAPIResponse(String name);
+
+    /**
+     * Returns a copy map (potentially immutable) of the APIResponses.
+     * 
+     * @return all responses
+     */
+    Map<String, APIResponse> getAPIResponses();
+
+    /**
+     * Set the APIResponses map to this APIResponses
+     * 
+     * @param items a map containing all responses. Keys are http statuses code eventually with wildcard or {@value #DEFAULT}.
+     */
+    void setAPIResponses(Map<String, APIResponse> items);
+
+    /**
+     * Check whether a APIResponse is present in the map. This is a convenience method for <code>getAPIResponses().containsKey(name)</code>
+     * 
+     * @param name the name of APIResponse (http status code eventually with wildcard or {@value #DEFAULT})
+     * @return a boolean to indicate if the APIResponse is present or not.
+     */
+    default boolean hasAPIResponse(String name) {
+        Map<String, APIResponse> map = getAPIResponses();
+        if (map == null) {
+            return false;
+        }
+        return map.containsKey(name);
+    }
+
+    /**
+     * Returns a APIResponse for a given name. This is a convenience method for <code>getAPIResponses().get(name)</code>
+     * 
+     * @param name the name of APIResponse (http status code eventually with wildcard or {@value #DEFAULT})
+     * @return the corresponding APIResponse or null.
+     */
+    default APIResponse getAPIResponse(String name) {
+        Map<String, APIResponse> map = getAPIResponses();
+        if (map == null) {
+            return null;
+        }
+        return map.get(name);
+    }
+
     /**
      * Returns the default documentation of responses other than the ones declared for specific HTTP response codes in this instance of ApiResponses.
      * <p>
-     * Convenience method that is the same as calling {@link #get(Object)} on the map with {@value #DEFAULT} as value for the key.
+     * Convenience method that is the same as calling {@link #getAPIResponse(String)} on the map with {@value #DEFAULT} as value for the key.
      * 
      * @return the default documentation of responses
      **/
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/security/Scopes.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/security/Scopes.java
index 639bf86..5d2ffb5 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/security/Scopes.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/security/Scopes.java
@@ -28,7 +28,7 @@ import org.eclipse.microprofile.openapi.models.Extensible;
  * @see <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#oauthFlowObject">OAuthFlow Object</a>
  **/
 
-public interface Scopes extends Constructible, Extensible<Scopes>, Map<String, String> {
+public interface Scopes extends Constructible, Extensible<Scopes> {
 
     /**
      * Adds name of an existing scope object and item parameters to a Scopes instance as a key-value pair in a map.
@@ -39,4 +39,53 @@ public interface Scopes extends Constructible, Extensible<Scopes>, Map<String, S
      */
     Scopes addScope(String scope, String description);
 
+    /**
+     * Removes the given scope item to this Scopes.
+     * 
+     * @param scope the name of a scope
+     */
+    void removeScope(String scope);
+
+    /**
+     * Returns a copy map (potentially immutable) of scopes.
+     * 
+     * @return all items
+     */
+    Map<String, String> getScopes();
+
+    /**
+     * Set the scope items map to this Scopes
+     * 
+     * @param items key-value pair in a map.
+     */
+    void setScopes(Map<String, String> items);
+
+    /**
+     * Check whether a scope item is present in the map. This is a convenience method for <code>getScopes().containsKey(name)</code>
+     * 
+     * @param scope the name of a scope.
+     * @return a boolean to indicate if the scope item is present or not.
+     */
+    default boolean hasScope(String scope) {
+        Map<String, String> map = getScopes();
+        if (map == null) {
+            return false;
+        }
+        return map.containsKey(scope);
+    }
+
+    /**
+     * Returns a scope description for a given scope name. This is a convenience method for <code>getScopes().get(name)</code>
+     * 
+     * @param scope the name of a scope.
+     * @return the corresponding description or null.
+     */
+    default String getScope(String scope) {
+        Map<String, String> map = getScopes();
+        if (map == null) {
+            return null;
+        }
+        return map.get(scope);
+    }
+
 }
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/security/SecurityRequirement.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/security/SecurityRequirement.java
index c925c93..88f0fc5 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/security/SecurityRequirement.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/security/SecurityRequirement.java
@@ -27,7 +27,7 @@ import org.eclipse.microprofile.openapi.models.Constructible;
  *
  * @see <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#security-requirement-object">SecurityRequirement Object</a>
  */
-public interface SecurityRequirement extends Constructible, Map<String, List<String>> {
+public interface SecurityRequirement extends Constructible {
 
     /**
      * Adds a security scheme to the SecurityRequirement instance based on the scheme name and 
@@ -59,4 +59,54 @@ public interface SecurityRequirement extends Constructible, Map<String, List<Str
      */
     SecurityRequirement addScheme(String securitySchemeName);
 
+    /**
+     * Removes a security scheme to the SecurityRequirement instance based on the scheme name.
+     * 
+     * @param securitySchemeName the name of security scheme
+     */
+    void removeScheme(String securitySchemeName);
+
+    /**
+     * Returns a copy map (potentially immutable) of the schemes.
+     * 
+     * @return all items
+     */
+    Map<String, List<String>> getSchemes();
+
+    /**
+     * Set all security schemes to the SecurityRequirement instance. Keys are the name of security scheme declared in the Components 
+     * section of the OpenAPI document, values are a list of required scope - only valid when the defined scheme is 'oauth2' or 'openIdConnect'
+     * 
+     * @param items a map containing the security schemes.
+     */
+    void setSchemes(Map<String, List<String>> items);
+
+    /**
+     * Check whether a scheme is present in the map. This is a convenience method for <code>getSchemes().containsKey(name)</code>
+     * 
+     * @param securitySchemeName the name of security scheme
+     * @return a boolean to indicate if the scheme is present or not.
+     */
+    default boolean hasScheme(String securitySchemeName) {
+        Map<String, List<String>> map = getSchemes();
+        if (map == null) {
+            return false;
+        }
+        return map.containsKey(securitySchemeName);
+    }
+
+    /**
+     * Returns a path item for a given name. This is a convenience method for <code>getSchemes().get(name)</code>
+     * 
+     * @param securitySchemeName the name of security scheme
+     * @return the corresponding path item or null.
+     */
+    default List<String> getScheme(String securitySchemeName) {
+        Map<String, List<String>> map = getSchemes();
+        if (map == null) {
+            return null;
+        }
+        return map.get(securitySchemeName);
+    }
+
 }
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/servers/ServerVariables.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/servers/ServerVariables.java
index 8842043..c9fd6af 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/servers/ServerVariables.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/servers/ServerVariables.java
@@ -27,7 +27,7 @@ import org.eclipse.microprofile.openapi.models.Extensible;
  *
  * @see <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#server-variable-object">ServerVariable Object</a>
  */
-public interface ServerVariables extends Constructible, Extensible<ServerVariables>, Map<String, ServerVariable> {
+public interface ServerVariables extends Constructible, Extensible<ServerVariables> {
 
     /**
      * This method adds a key-value item to a ServerVariables instance from the name-item parameter pair and returns the modified instance.
@@ -38,4 +38,53 @@ public interface ServerVariables extends Constructible, Extensible<ServerVariabl
      */
     ServerVariables addServerVariable(String name, ServerVariable serverVariable);
 
+    /**
+     * Removes the given server variables.
+     * 
+     * @param name the name of ServerVariable instance
+     */
+    void removeServerVariable(String name);
+
+    /**
+     * Returns a copy map (potentially immutable) of the server variables.
+     * 
+     * @return all items
+     */
+    Map<String, ServerVariable> getServerVariables();
+
+    /**
+     * Set the server variables map to this ServerVariables object.
+     * 
+     * @param items a map containing key-value item.
+     */
+    void setServerVariables(Map<String, ServerVariable> items);
+
+    /**
+     * Check whether a server variable is present in the map. This is a convenience method for <code>getServerVariables().containsKey(name)</code>
+     * 
+     * @param name the name of ServerVariable instance
+     * @return a boolean to indicate if the server variable is present or not.
+     */
+    default boolean hasServerVariable(String name) {
+        Map<String, ServerVariable> map = getServerVariables();
+        if (map == null) {
+            return false;
+        }
+        return map.containsKey(name);
+    }
+
+    /**
+     * Returns a server variable for a given name. This is a convenience method for <code>getServerVariables().get(name)</code>
+     * 
+     * @param name the name of ServerVariable instance
+     * @return the corresponding server variable or null.
+     */
+    default ServerVariable getServerVariable(String name) {
+        Map<String, ServerVariable> map = getServerVariables();
+        if (map == null) {
+            return null;
+        }
+        return map.get(name);
+    }
+
 }
\ No newline at end of file
diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/filter/AirlinesOASFilter.java b/tck/src/main/java/org/eclipse/microprofile/openapi/filter/AirlinesOASFilter.java
index 941100a..b08852b 100644
--- a/tck/src/main/java/org/eclipse/microprofile/openapi/filter/AirlinesOASFilter.java
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/filter/AirlinesOASFilter.java
@@ -55,11 +55,11 @@ public class AirlinesOASFilter implements OASFilter {
             Map<String, Callback> callbacks = pathItem.getPOST().getCallbacks();
             if (callbacks.containsKey("bookingCallback")) {
                 Callback callback = callbacks.get("bookingCallback");
-                if (callback.containsKey("http://localhost:9080/airlines/bookings")
-                        && callback.get("http://localhost:9080/airlines/bookings").getGET() != null) {
-                    if ("child - Retrieve all bookings for current user".equals(callback.get("http://localhost:9080/airlines/bookings")
+                if (callback.hasPathItem("http://localhost:9080/airlines/bookings")
+                        && callback.getPathItem("http://localhost:9080/airlines/bookings").getGET() != null) {
+                    if ("child - Retrieve all bookings for current user".equals(callback.getPathItem("http://localhost:9080/airlines/bookings")
                             .getGET().getDescription())) {   
-                        callback.get("http://localhost:9080/airlines/bookings").getGET()
+                        callback.getPathItem("http://localhost:9080/airlines/bookings").getGET()
                         .setDescription("parent - Retrieve all bookings for current user"); 
                     }
                 }
@@ -127,8 +127,8 @@ public class AirlinesOASFilter implements OASFilter {
         // testing child before parent filtering
         Content content = apiResponse.getContent();
         if (content != null) {
-            if (content.containsKey("application/json")) {
-                Schema schema = content.get("application/json").getSchema();
+            if (content.hasMediaType("application/json")) {
+                Schema schema = content.getMediaType("application/json").getSchema();
                 if ("child - id of the new review".equals(schema.getDescription())) {
                     schema.setDescription("parent - id of the new review");
                 }
@@ -190,13 +190,13 @@ public class AirlinesOASFilter implements OASFilter {
 
     @Override
     public Callback filterCallback(Callback callback) {
-        if(callback.containsKey("{$request.query.callbackUrl}/data") && callback.get("{$request.query.callbackUrl}/data").getPOST() != null){
-            callback.get("{$request.query.callbackUrl}/data").getPOST().setDescription("filterCallback - callback post operation");
+        if(callback.hasPathItem("{$request.query.callbackUrl}/data") && callback.getPathItem("{$request.query.callbackUrl}/data").getPOST() != null){
+            callback.getPathItem("{$request.query.callbackUrl}/data").getPOST().setDescription("filterCallback - callback post operation");
         }
         
-        if (callback.containsKey("http://localhost:9080/airlines/bookings") 
-                && callback.get("http://localhost:9080/airlines/bookings").getGET() != null) {
-            callback.get("http://localhost:9080/airlines/bookings").getGET().setDescription("child - Retrieve all bookings for current user");
+        if (callback.hasPathItem("http://localhost:9080/airlines/bookings") 
+                && callback.getPathItem("http://localhost:9080/airlines/bookings").getGET() != null) {
+            callback.getPathItem("http://localhost:9080/airlines/bookings").getGET().setDescription("child - Retrieve all bookings for current user");
         }
         return callback;
     }
@@ -205,6 +205,6 @@ public class AirlinesOASFilter implements OASFilter {
     public void filterOpenAPI(OpenAPI openAPI) {
         //Spec states : The filterOpenAPI method must be the last method called on a filter (which is just a specialization of the first exception).
         //To ensure that this method is called last, override the operation summary that was previously overridden in filterOperation method
-        openAPI.getPaths().get("/bookings/{id}").getPUT().setSummary("filterOpenAPI - Update a booking with ID");
+        openAPI.getPaths().getPathItem("/bookings/{id}").getPUT().setSummary("filterOpenAPI - Update a booking with ID");
     }
 }


Test patch:
diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java
index bd8ce6b..14fd6b1 100644
--- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java
@@ -35,6 +35,7 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 import org.eclipse.microprofile.openapi.OASFactory;
 import org.eclipse.microprofile.openapi.models.Components;
@@ -369,31 +370,29 @@ public class ModelConstructionTest {
         assertTrue(p.hasPathItem(pathItemKey), pathItemKey + " is present in the map");
         assertSame(p.getPathItem(pathItemKey), pathItemValue, 
                 "The value associated with the key: " + pathItemKey + " is expected to be the same one that was added.");
-        checkMapEntry(p, pathItemKey, pathItemValue);
         checkMapEntry(p.getPathItems(), pathItemKey, pathItemValue);
         
         final String pathItemKey2 = "/myPathItem2";
         assertFalse(p.hasPathItem(pathItemKey2), pathItemKey2 + " is absent in the map");
         final PathItem pathItemValue2 = createConstructibleInstance(PathItem.class);
-        assertNull(p.put(pathItemKey2, pathItemValue2), "No previous mapping expected.");
+        checkSameObject(p, p.addPathItem(pathItemKey2, pathItemValue2));
         assertTrue(p.hasPathItem(pathItemKey2), pathItemKey2 + " is present in the map");
         assertSame(p.getPathItem(pathItemKey2), pathItemValue2, 
                 "The value associated with the key: " + pathItemKey2 + " is expected to be the same one that was added.");
-        checkMapEntry(p, pathItemKey2, pathItemValue2);
         checkMapEntry(p.getPathItems(), pathItemKey2, pathItemValue2);
         
-        assertEquals(p.size(), 2, "The map is expected to contain two entries.");
         assertEquals(p.getPathItems().size(), 2, "The map is expected to contain two entries.");
         
         p.removePathItem(pathItemKey);
         assertFalse(p.hasPathItem(pathItemKey), pathItemKey + " is absent in the map");
-        assertEquals(p.size(), 1, "The map is expected to contain two entries.");
-        assertEquals(p.getPathItems().size(), 1, "The map is expected to contain two entries.");
+        assertEquals(p.getPathItems().size(), 1, "The map is expected to contain one entry.");
         
-        p.remove(pathItemKey2);
+        p.removePathItem(pathItemKey2);
         assertFalse(p.hasPathItem(pathItemKey2), pathItemKey + " is absent in the map");
-        assertEquals(p.size(), 0, "The map is expected to contain 0 entries.");
         assertEquals(p.getPathItems().size(), 0, "The map is expected to contain 0 entries.");
+        
+        final PathItem otherValue = createConstructibleInstance(PathItem.class);
+        checkMapImmutable(p, Paths::getPathItems, "/otherPathItem", otherValue);
     }
     
     @Test
@@ -401,16 +400,35 @@ public class ModelConstructionTest {
         final Callback c = processConstructible(Callback.class);
         
         final String pathItemKey = "myPathItem";
+        assertFalse(c.hasPathItem(pathItemKey), pathItemKey + " is absent in the map");
         final PathItem pathItemValue = createConstructibleInstance(PathItem.class);
         checkSameObject(c, c.addPathItem(pathItemKey, pathItemValue));
-        checkMapEntry(c, pathItemKey, pathItemValue);
+        assertTrue(c.hasPathItem(pathItemKey), pathItemKey + " is present in the map");
+        assertSame(c.getPathItem(pathItemKey), pathItemValue, 
+                "The value associated with the key: " + pathItemKey + " is expected to be the same one that was added.");
+        checkMapEntry(c.getPathItems(), pathItemKey, pathItemValue);
         
         final String pathItemKey2 = "myPathItem2";
+        assertFalse(c.hasPathItem(pathItemKey2), pathItemKey2 + " is absent in the map");
         final PathItem pathItemValue2 = createConstructibleInstance(PathItem.class);
-        assertNull(c.put(pathItemKey2, pathItemValue2), "No previous mapping expected.");
-        checkMapEntry(c, pathItemKey2, pathItemValue2);
+        checkSameObject(c, c.addPathItem(pathItemKey2, pathItemValue2));
+        assertTrue(c.hasPathItem(pathItemKey2), pathItemKey2 + " is present in the map");
+        assertSame(c.getPathItem(pathItemKey2), pathItemValue2, 
+                "The value associated with the key: " + pathItemKey2 + " is expected to be the same one that was added.");
+        checkMapEntry(c.getPathItems(), pathItemKey2, pathItemValue2);
+        
+        assertEquals(c.getPathItems().size(), 2, "The map is expected to contain two entries.");
         
-        assertEquals(c.size(), 2, "The map is expected to contain two entries.");
+        c.removePathItem(pathItemKey);
+        assertFalse(c.hasPathItem(pathItemKey), pathItemKey + " is absent in the map");
+        assertEquals(c.getPathItems().size(), 1, "The map is expected to contain one entry.");
+        
+        c.removePathItem(pathItemKey2);
+        assertFalse(c.hasPathItem(pathItemKey2), pathItemKey + " is absent in the map");
+        assertEquals(c.getPathItems().size(), 0, "The map is expected to contain 0 entries.");
+        
+        final PathItem otherValue = createConstructibleInstance(PathItem.class);
+        checkMapImmutable(c, Callback::getPathItems, "otherPathItem", otherValue);
     }
     
     @Test
@@ -463,17 +481,36 @@ public class ModelConstructionTest {
     public void contentTest() {
         final Content c = processConstructible(Content.class);
         
-        final String mediaTypeKey = "myPathItem";
+        final String mediaTypeKey = "application/json";
+        assertFalse(c.hasMediaType(mediaTypeKey), mediaTypeKey + " is absent in the map");
         final MediaType mediaTypeValue = createConstructibleInstance(MediaType.class);
         checkSameObject(c, c.addMediaType(mediaTypeKey, mediaTypeValue));
-        checkMapEntry(c, mediaTypeKey, mediaTypeValue);
+        assertTrue(c.hasMediaType(mediaTypeKey), mediaTypeKey + " is present in the map");
+        assertSame(c.getMediaType(mediaTypeKey), mediaTypeValue, 
+                "The value associated with the key: " + mediaTypeKey + " is expected to be the same one that was added.");
+        checkMapEntry(c.getMediaTypes(), mediaTypeKey, mediaTypeValue);
         
-        final String mediaTypeKey2 = "myPathItem2";
+        final String mediaTypeKey2 = "*/*";
+        assertFalse(c.hasMediaType(mediaTypeKey2), mediaTypeKey2 + " is absent in the map");
         final MediaType mediaTypeValue2 = createConstructibleInstance(MediaType.class);
-        assertNull(c.put(mediaTypeKey2, mediaTypeValue2), "No previous mapping expected.");
-        checkMapEntry(c, mediaTypeKey2, mediaTypeValue2);
+        checkSameObject(c, c.addMediaType(mediaTypeKey2, mediaTypeValue2));
+        assertTrue(c.hasMediaType(mediaTypeKey2), mediaTypeKey2 + " is present in the map");
+        assertSame(c.getMediaType(mediaTypeKey2), mediaTypeValue2, 
+                "The value associated with the key: " + mediaTypeKey2 + " is expected to be the same one that was added.");
+        checkMapEntry(c.getMediaTypes(), mediaTypeKey2, mediaTypeValue2);
+        
+        assertEquals(c.getMediaTypes().size(), 2, "The map is expected to contain two entries.");
         
-        assertEquals(c.size(), 2, "The map is expected to contain two entries.");
+        c.removeMediaType(mediaTypeKey);
+        assertFalse(c.hasMediaType(mediaTypeKey), mediaTypeKey + " is absent in the map");
+        assertEquals(c.getMediaTypes().size(), 1, "The map is expected to contain one entry.");
+        
+        c.removeMediaType(mediaTypeKey2);
+        assertFalse(c.hasMediaType(mediaTypeKey2), mediaTypeKey + " is absent in the map");
+        assertEquals(c.getMediaTypes().size(), 0, "The map is expected to contain 0 entries.");
+        
+        final MediaType otherValue = createConstructibleInstance(MediaType.class);
+        checkMapImmutable(c, Content::getMediaTypes, "application/txt", otherValue);
     }
     
     @Test
@@ -633,37 +670,58 @@ public class ModelConstructionTest {
     public void apiResponsesTest() {
         final APIResponses responses = processConstructible(APIResponses.class);
         
-        responses.remove(APIResponses.DEFAULT);
-        assertEquals(responses.size(), 0, "The map is expected to contain two entries.");
+        responses.removeAPIResponse(APIResponses.DEFAULT);
+        if(responses.getAPIResponses() != null) {
+            assertEquals(responses.getAPIResponses().size(), 0, "The map is expected to contain two entries.");
+        }
         
         final String responseKey = "200";
-        final APIResponse responseValue = createConstructibleInstance(APIResponse.class);
-        checkSameObject(responses, responses.addAPIResponse(responseKey, responseValue));
-        checkMapEntry(responses, responseKey, responseValue);
+        assertFalse(responses.hasAPIResponse(responseKey), responseKey + " is absent in the map");
+        final APIResponse pathItemValue = createConstructibleInstance(APIResponse.class);
+        checkSameObject(responses, responses.addAPIResponse(responseKey, pathItemValue));
+        assertTrue(responses.hasAPIResponse(responseKey), responseKey + " is present in the map");
+        assertSame(responses.getAPIResponse(responseKey), pathItemValue, 
+                "The value associated with the key: " + responseKey + " is expected to be the same one that was added.");
+        checkMapEntry(responses.getAPIResponses(), responseKey, pathItemValue);
         
         final String responseKey2 = "4XX";
-        final APIResponse responseValue2 = createConstructibleInstance(APIResponse.class);
-        assertNull(responses.put(responseKey2, responseValue2), "No previous mapping expected.");
-        checkMapEntry(responses, responseKey2, responseValue2);
+        assertFalse(responses.hasAPIResponse(responseKey2), responseKey2 + " is absent in the map");
+        final APIResponse pathItemValue2 = createConstructibleInstance(APIResponse.class);
+        checkSameObject(responses, responses.addAPIResponse(responseKey2, pathItemValue2));
+        assertTrue(responses.hasAPIResponse(responseKey2), responseKey2 + " is present in the map");
+        assertSame(responses.getAPIResponse(responseKey2), pathItemValue2, 
+                "The value associated with the key: " + responseKey2 + " is expected to be the same one that was added.");
+        checkMapEntry(responses.getAPIResponses(), responseKey2, pathItemValue2);
+        
+        assertEquals(responses.getAPIResponses().size(), 2, "The map is expected to contain two entries.");
+        
+        responses.removeAPIResponse(responseKey);
+        assertFalse(responses.hasAPIResponse(responseKey), responseKey + " is absent in the map");
+        assertEquals(responses.getAPIResponses().size(), 1, "The map is expected to contain one entry.");
+        
+        responses.removeAPIResponse(responseKey2);
+        assertFalse(responses.hasAPIResponse(responseKey2), responseKey + " is absent in the map");
+        assertEquals(responses.getAPIResponses().size(), 0, "The map is expected to contain 0 entries.");
         
-        assertEquals(responses.size(), 2, "The map is expected to contain two entries.");
+        final APIResponse otherValue = createConstructibleInstance(APIResponse.class);
+        checkMapImmutable(responses, APIResponses::getAPIResponses, "500", otherValue);
         
         assertNull(responses.getDefaultValue(), "No default value expected.");
         final String responseKey3 = APIResponses.DEFAULT;
         final APIResponse responseValue3 = createConstructibleInstance(APIResponse.class);
-        assertNull(responses.put(responseKey3, responseValue3), "No previous mapping expected.");
-        checkMapEntry(responses, responseKey3, responseValue3);
+        checkSameObject(responses, responses.addAPIResponse(responseKey3, responseValue3));
+        checkMapEntry(responses.getAPIResponses(), responseKey3, responseValue3);
         checkSameObject(responseValue3, responses.getDefaultValue());
         
-        assertEquals(responses.size(), 3, "The map is expected to contain two entries.");
+        assertEquals(responses.getAPIResponses().size(), 1, "The map is expected to contain one entry.");
         
         responses.setDefaultValue(null);
-        assertNull(responses.get(APIResponses.DEFAULT), "No default value expected.");
+        assertNull(responses.getAPIResponse(APIResponses.DEFAULT), "No default value expected.");
         assertNull(responses.getDefaultValue(), "No default value expected.");
         
         final APIResponse responseValue4 = createConstructibleInstance(APIResponse.class);
         responses.setDefaultValue(responseValue4);
-        checkMapEntry(responses, APIResponses.DEFAULT, responseValue4);
+        checkMapEntry(responses.getAPIResponses(), APIResponses.DEFAULT, responseValue4);
         checkSameObject(responseValue4, responses.getDefaultValue());
     }
     
@@ -682,33 +740,71 @@ public class ModelConstructionTest {
         final Scopes s = processConstructible(Scopes.class);
         
         final String scopeKey = "myScope";
+        assertFalse(s.hasScope(scopeKey), scopeKey + " is absent in the map");
         final String scopeValue = new String("myDescription");
         checkSameObject(s, s.addScope(scopeKey, scopeValue));
-        checkMapEntry(s, scopeKey, scopeValue);
+        assertTrue(s.hasScope(scopeKey), scopeKey + " is present in the map");
+        assertSame(s.getScope(scopeKey), scopeValue, 
+                "The value associated with the key: " + scopeKey + " is expected to be the same one that was added.");
+        checkMapEntry(s.getScopes(), scopeKey, scopeValue);
         
         final String scopeKey2 = "myScope2";
+        assertFalse(s.hasScope(scopeKey2), scopeKey2 + " is absent in the map");
         final String scopeValue2 = new String("myDescription2");
-        assertNull(s.put(scopeKey2, scopeValue2), "No previous mapping expected.");
-        checkMapEntry(s, scopeKey2, scopeValue2);
+        checkSameObject(s, s.addScope(scopeKey2, scopeValue2));
+        assertTrue(s.hasScope(scopeKey2), scopeKey2 + " is present in the map");
+        assertSame(s.getScope(scopeKey2), scopeValue2, 
+                "The value associated with the key: " + scopeKey2 + " is expected to be the same one that was added.");
+        checkMapEntry(s.getScopes(), scopeKey2, scopeValue2);
         
-        assertEquals(s.size(), 2, "The map is expected to contain two entries.");
+        assertEquals(s.getScopes().size(), 2, "The map is expected to contain two entries.");
+        
+        s.removeScope(scopeKey);
+        assertFalse(s.hasScope(scopeKey), scopeKey + " is absent in the map");
+        assertEquals(s.getScopes().size(), 1, "The map is expected to contain one entry.");
+        
+        s.removeScope(scopeKey2);
+        assertFalse(s.hasScope(scopeKey2), scopeKey + " is absent in the map");
+        assertEquals(s.getScopes().size(), 0, "The map is expected to contain 0 entries.");
+        
+        final String otherValue = new String("otherDescription");
+        checkMapImmutable(s, Scopes::getScopes, "otherScope", otherValue);
     }
     
     @Test
     public void securityRequirementTest() {
         final SecurityRequirement sr = processConstructible(SecurityRequirement.class);
         
-        final String schemeKey = "myResponse";
+        final String schemeKey = "myScheme";
+        assertFalse(sr.hasScheme(schemeKey), schemeKey + " is absent in the map");
         final List<String> schemeValue = new ArrayList<String>();
         checkSameObject(sr, sr.addScheme(schemeKey, schemeValue));
-        checkMapEntry(sr, schemeKey, schemeValue);
+        assertTrue(sr.hasScheme(schemeKey), schemeKey + " is present in the map");
+        assertSame(sr.getScheme(schemeKey), schemeValue, 
+                "The value associated with the key: " + schemeKey + " is expected to be the same one that was added.");
+        checkMapEntry(sr.getSchemes(), schemeKey, schemeValue);
         
-        final String schemeKey2 = "myResponse2";
+        final String schemeKey2 = "myScheme2";
+        assertFalse(sr.hasScheme(schemeKey2), schemeKey2 + " is absent in the map");
         final List<String> schemeValue2 = new ArrayList<String>();
-        assertNull(sr.put(schemeKey2, schemeValue2), "No previous mapping expected.");
-        checkMapEntry(sr, schemeKey2, schemeValue2);
+        checkSameObject(sr, sr.addScheme(schemeKey2, schemeValue2));
+        assertTrue(sr.hasScheme(schemeKey2), schemeKey2 + " is present in the map");
+        assertSame(sr.getScheme(schemeKey2), schemeValue2, 
+                "The value associated with the key: " + schemeKey2 + " is expected to be the same one that was added.");
+        checkMapEntry(sr.getSchemes(), schemeKey2, schemeValue2);
+        
+        assertEquals(sr.getSchemes().size(), 2, "The map is expected to contain two entries.");
         
-        assertEquals(sr.size(), 2, "The map is expected to contain two entries.");
+        sr.removeScheme(schemeKey);
+        assertFalse(sr.hasScheme(schemeKey), schemeKey + " is absent in the map");
+        assertEquals(sr.getSchemes().size(), 1, "The map is expected to contain one entry.");
+        
+        sr.removeScheme(schemeKey2);
+        assertFalse(sr.hasScheme(schemeKey2), schemeKey + " is absent in the map");
+        assertEquals(sr.getSchemes().size(), 0, "The map is expected to contain 0 entries.");
+        
+        final List<String> otherValue = new ArrayList<String>();
+        checkMapImmutable(sr, SecurityRequirement::getSchemes, "otherScheme", otherValue);
     }
     
     @Test
@@ -738,16 +834,35 @@ public class ModelConstructionTest {
         final ServerVariables svs = processConstructible(ServerVariables.class);
         
         final String varKey = "myServerVariable";
+        assertFalse(svs.hasServerVariable(varKey), varKey + " is absent in the map");
         final ServerVariable varValue = createConstructibleInstance(ServerVariable.class);
         checkSameObject(svs, svs.addServerVariable(varKey, varValue));
-        checkMapEntry(svs, varKey, varValue);
+        assertTrue(svs.hasServerVariable(varKey), varKey + " is present in the map");
+        assertSame(svs.getServerVariable(varKey), varValue, 
+                "The value associated with the key: " + varKey + " is expected to be the same one that was added.");
+        checkMapEntry(svs.getServerVariables(), varKey, varValue);
         
         final String varKey2 = "myServerVariable2";
+        assertFalse(svs.hasServerVariable(varKey2), varKey2 + " is absent in the map");
         final ServerVariable varValue2 = createConstructibleInstance(ServerVariable.class);
-        assertNull(svs.put(varKey2, varValue2), "No previous mapping expected.");
-        checkMapEntry(svs, varKey2, varValue2);
+        checkSameObject(svs, svs.addServerVariable(varKey2, varValue2));
+        assertTrue(svs.hasServerVariable(varKey2), varKey2 + " is present in the map");
+        assertSame(svs.getServerVariable(varKey2), varValue2, 
+                "The value associated with the key: " + varKey2 + " is expected to be the same one that was added.");
+        checkMapEntry(svs.getServerVariables(), varKey2, varValue2);
+        
+        assertEquals(svs.getServerVariables().size(), 2, "The map is expected to contain two entries.");
         
-        assertEquals(svs.size(), 2, "The map is expected to contain two entries.");
+        svs.removeServerVariable(varKey);
+        assertFalse(svs.hasServerVariable(varKey), varKey + " is absent in the map");
+        assertEquals(svs.getServerVariables().size(), 1, "The map is expected to contain one entry.");
+        
+        svs.removeServerVariable(varKey2);
+        assertFalse(svs.hasServerVariable(varKey2), varKey + " is absent in the map");
+        assertEquals(svs.getServerVariables().size(), 0, "The map is expected to contain 0 entries.");
+        
+        final ServerVariable otherValue = createConstructibleInstance(ServerVariable.class);
+        checkMapImmutable(svs, ServerVariables::getServerVariables, "otherServerVariable", otherValue);
     }
     
     @Test
@@ -845,7 +960,7 @@ public class ModelConstructionTest {
     private void processConstructibleProperty(Constructible o, Property p, Class<?> enclosingInterface) {
         final Object value1 = getInstanceOf(p.getType(), false);
         p.invokeSetter(o, value1);
-        if (!p.isPrimitive()) {
+        if (!p.isPrimitive() && !p.isCompatible(Map.class)) {
             assertSame(p.invokeGetter(o), value1, "The return value of the getter method for property \"" + 
                     p.getName() + "\" of interface \"" + enclosingInterface.getName() +
                     "\" is expected to be the same as the value that was set.");
@@ -1032,6 +1147,23 @@ public class ModelConstructionTest {
         assertTrue(map.containsKey(key), "The map is expected to contain the key: " + key);
         assertSame(map.get(key), value, "The value associated with the key: " + key + " is expected to be the same one that was added.");
     }
+
+    private <O, K, T> void checkMapImmutable(O container, Function<O, Map<K,T>> mapGetter, K key, T otherValue) {
+        Map<K,T> map = mapGetter.apply(container);
+        assertNotNull(map, "The map must not be null.");
+        assertFalse(map.containsKey(key), "The map is expected to not contain the key: " + key);
+        int originalSize = map.size();
+        try {
+            map.put(key, otherValue);
+        }
+        catch (Exception e) {
+            //It is allowed to throw an exception
+        }
+        Map<K,T> map2 = mapGetter.apply(container);
+        assertNotNull(map2, "The map must not be null.");
+        assertFalse(map2.containsKey(key), "The map is expected to not contain the key: " + key);
+        assertEquals(map2.size(), originalSize, "The map is expected to have a size of " + originalSize);
+    }
     
     private <T> void checkListEntry(List<T> list, T value) {
         assertNotNull(list, "The list must not be null.");