-
Notifications
You must be signed in to change notification settings - Fork 271
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Proposed change to the Maven Plugin: Auto References (#3439)
* Added a new ReferenceFinder component for artifacts (per-type). Added a proposed change to the maven plugin to auto detect refs * Added a ref finder for JSON Schema
- Loading branch information
1 parent
4b31c9f
commit 8394e10
Showing
37 changed files
with
1,814 additions
and
32 deletions.
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
...til/asyncapi/src/main/java/io/apicurio/registry/content/refs/AsyncApiReferenceFinder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* Copyright 2023 Red Hat Inc | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.apicurio.registry.content.refs; | ||
|
||
/** | ||
* OpenAPI implementation of a reference finder. Parses the OpenAPI document, finds all $refs, converts them | ||
* to external references, and returns them. | ||
* @author [email protected] | ||
*/ | ||
public class AsyncApiReferenceFinder extends AbstractDataModelsReferenceFinder { | ||
|
||
} |
105 changes: 105 additions & 0 deletions
105
schema-util/avro/src/main/java/io/apicurio/registry/content/refs/AvroReferenceFinder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
* Copyright 2023 Red Hat Inc | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.apicurio.registry.content.refs; | ||
|
||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.databind.node.ArrayNode; | ||
|
||
import io.apicurio.registry.content.ContentHandle; | ||
|
||
/** | ||
* An Apache Avro implementation of a reference finder. | ||
* @author [email protected] | ||
*/ | ||
public class AvroReferenceFinder implements ReferenceFinder { | ||
|
||
private static final ObjectMapper mapper = new ObjectMapper(); | ||
private static final Logger log = LoggerFactory.getLogger(AvroReferenceFinder.class); | ||
|
||
private static final Set<String> PRIMITIVE_TYPES = Set.of("null", "boolean", "int", "long", "float", "double", "bytes", "string"); | ||
|
||
/** | ||
* @see io.apicurio.registry.content.refs.ReferenceFinder#findExternalReferences(io.apicurio.registry.content.ContentHandle) | ||
*/ | ||
@Override | ||
public Set<ExternalReference> findExternalReferences(ContentHandle content) { | ||
try { | ||
JsonNode tree = mapper.readTree(content.content()); | ||
Set<String> externalTypes = new HashSet<>(); | ||
findExternalTypesIn(tree, externalTypes); | ||
return externalTypes.stream().map(type -> new ExternalReference(type)).collect(Collectors.toSet()); | ||
} catch (Exception e) { | ||
log.error("Error finding external references in an Avro file.", e); | ||
return Collections.emptySet(); | ||
} | ||
} | ||
|
||
private static void findExternalTypesIn(JsonNode schema, Set<String> externalTypes) { | ||
// Null check | ||
if (schema == null || schema.isNull()) { | ||
return; | ||
} | ||
|
||
// Handle primitive/external types | ||
if (schema.isTextual()) { | ||
String type = schema.asText(); | ||
if (!PRIMITIVE_TYPES.contains(type)) { | ||
externalTypes.add(type); | ||
} | ||
} | ||
|
||
// Handle unions | ||
if (schema.isArray()) { | ||
ArrayNode schemas = (ArrayNode) schema; | ||
schemas.forEach(s -> findExternalTypesIn(s, externalTypes)); | ||
} | ||
|
||
// Handle records | ||
if (schema.isObject() && schema.has("type") && !schema.get("type").isNull() && schema.get("type").asText().equals("record")) { | ||
JsonNode fieldsNode = schema.get("fields"); | ||
if (fieldsNode != null && fieldsNode.isArray()) { | ||
ArrayNode fields = (ArrayNode) fieldsNode; | ||
fields.forEach(fieldNode -> { | ||
if (fieldNode.isObject()) { | ||
JsonNode typeNode = fieldNode.get("type"); | ||
findExternalTypesIn(typeNode, externalTypes); | ||
} | ||
}); | ||
} | ||
} | ||
// Handle arrays | ||
if (schema.has("type") && !schema.get("type").isNull() && schema.get("type").asText().equals("array")) { | ||
JsonNode items = schema.get("items"); | ||
findExternalTypesIn(items, externalTypes); | ||
} | ||
// Handle maps | ||
if (schema.has("type") && !schema.get("type").isNull() && schema.get("type").asText().equals("map")) { | ||
JsonNode values = schema.get("values"); | ||
findExternalTypesIn(values, externalTypes); | ||
} | ||
} | ||
|
||
} |
150 changes: 150 additions & 0 deletions
150
schema-util/common/src/main/java/io/apicurio/registry/content/refs/ExternalReference.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
/* | ||
* Copyright 2023 Red Hat Inc | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.apicurio.registry.content.refs; | ||
|
||
import java.util.Objects; | ||
|
||
/** | ||
* Models a reference from one artifact to another. This represents the information found in the content | ||
* of an artifact, and is very type-specific. For example, a JSON schema reference might look like this: | ||
* | ||
* <pre> | ||
* { | ||
* "$ref" : "types/data-types.json#/$defs/FooType" | ||
* } | ||
* </pre> | ||
* | ||
* In this case, the fields of this type will be: | ||
* | ||
* <ul> | ||
* <li><em>fullReference</em>: <code>types/data-types.json#/$defs/FooType</code></li> | ||
* <li><em>resource</em>: <code>types/data-types.json</code></li> | ||
* <li><em>component</em>: <code>#/$defs/FooType</code></li> | ||
* </ul> | ||
* | ||
* For an Avro artifact a reference might look like this: | ||
* | ||
* <pre> | ||
* { | ||
* "name": "exchange", | ||
* "type": "com.kubetrade.schema.common.Exchange" | ||
* } | ||
* </pre> | ||
* | ||
* In this case, the fields of this type will be: | ||
* | ||
* <ul> | ||
* <li><em>fullReference</em>: <code>com.kubetrade.schema.common.Exchange</code></li> | ||
* <li><em>resource</em>: <code>com.kubetrade.schema.common.Exchange</code></li> | ||
* <li><em>component</em>: <em>null</em></li> | ||
* </ul> | ||
* | ||
* @author [email protected] | ||
*/ | ||
public class ExternalReference { | ||
|
||
private String fullReference; | ||
private String resource; | ||
private String component; | ||
|
||
/** | ||
* Constructor. | ||
* @param fullReference | ||
* @param resource | ||
* @param component | ||
*/ | ||
public ExternalReference(String fullReference, String resource, String component) { | ||
this.fullReference = fullReference; | ||
this.resource = resource; | ||
this.component = component; | ||
} | ||
|
||
/** | ||
* Constructor. This variant is useful if there is no component part of an external reference. In this | ||
* case the full reference is also the resource (and the component is null). | ||
* @param reference | ||
*/ | ||
public ExternalReference(String reference) { | ||
this(reference, reference, null); | ||
} | ||
|
||
/** | ||
* @return the fullReference | ||
*/ | ||
public String getFullReference() { | ||
return fullReference; | ||
} | ||
|
||
/** | ||
* @param fullReference the fullReference to set | ||
*/ | ||
public void setFullReference(String fullReference) { | ||
this.fullReference = fullReference; | ||
} | ||
|
||
/** | ||
* @return the resource | ||
*/ | ||
public String getResource() { | ||
return resource; | ||
} | ||
|
||
/** | ||
* @param resource the resource to set | ||
*/ | ||
public void setResource(String resource) { | ||
this.resource = resource; | ||
} | ||
|
||
/** | ||
* @return the component | ||
*/ | ||
public String getComponent() { | ||
return component; | ||
} | ||
|
||
/** | ||
* @param component the component to set | ||
*/ | ||
public void setComponent(String component) { | ||
this.component = component; | ||
} | ||
|
||
/** | ||
* @see java.lang.Object#hashCode() | ||
*/ | ||
@Override | ||
public int hashCode() { | ||
return Objects.hash(fullReference); | ||
} | ||
|
||
/** | ||
* @see java.lang.Object#equals(java.lang.Object) | ||
*/ | ||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) | ||
return true; | ||
if (obj == null) | ||
return false; | ||
if (getClass() != obj.getClass()) | ||
return false; | ||
ExternalReference other = (ExternalReference) obj; | ||
return Objects.equals(fullReference, other.fullReference); | ||
} | ||
|
||
} |
54 changes: 54 additions & 0 deletions
54
.../common/src/main/java/io/apicurio/registry/content/refs/JsonPointerExternalReference.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright 2023 Red Hat Inc | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.apicurio.registry.content.refs; | ||
|
||
/** | ||
* @author [email protected] | ||
*/ | ||
public class JsonPointerExternalReference extends ExternalReference { | ||
|
||
/** | ||
* Constructor. | ||
* @param jsonPointer | ||
*/ | ||
public JsonPointerExternalReference(String jsonPointer) { | ||
super(jsonPointer, resourceFrom(jsonPointer), componentFrom(jsonPointer)); | ||
} | ||
|
||
private static String componentFrom(String jsonPointer) { | ||
int idx = jsonPointer.indexOf('#'); | ||
if (idx == 0) { | ||
return jsonPointer; | ||
} else if (idx > 0) { | ||
return jsonPointer.substring(idx); | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
private static String resourceFrom(String jsonPointer) { | ||
int idx = jsonPointer.indexOf('#'); | ||
if (idx == 0) { | ||
return null; | ||
} else if (idx > 0) { | ||
return jsonPointer.substring(0, idx); | ||
} else { | ||
return jsonPointer; | ||
} | ||
} | ||
|
||
} |
39 changes: 39 additions & 0 deletions
39
schema-util/common/src/main/java/io/apicurio/registry/content/refs/NoOpReferenceFinder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* Copyright 2023 Red Hat Inc | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.apicurio.registry.content.refs; | ||
|
||
import java.util.Collections; | ||
import java.util.Set; | ||
|
||
import io.apicurio.registry.content.ContentHandle; | ||
|
||
/** | ||
* @author [email protected] | ||
*/ | ||
public class NoOpReferenceFinder implements ReferenceFinder { | ||
|
||
public static final ReferenceFinder INSTANCE = new NoOpReferenceFinder(); | ||
|
||
/** | ||
* @see io.apicurio.registry.content.refs.ReferenceFinder#findExternalReferences(io.apicurio.registry.content.ContentHandle) | ||
*/ | ||
@Override | ||
public Set<ExternalReference> findExternalReferences(ContentHandle content) { | ||
return Collections.emptySet(); | ||
} | ||
|
||
} |
Oops, something went wrong.