Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposed change to the Maven Plugin: Auto References #3439

Merged
merged 2 commits into from
Jun 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {

}
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);
}
}

}
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);
}

}
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;
}
}

}
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();
}

}
Loading