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

160 scs multiapi plugin homogenize code generation in openapi and asyncapi #200

Conversation

eduardofrancosngular
Copy link

Code refactoring to use JsonNode instead of swagger apis

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for collaborating with the project to help us improve!

@github-actions
Copy link

This pull request hasn't been labeled as release nor documentation. Please ensure this is intentional before merging.


public final class Constants {

public static final String INTEGER = "integer";
Copy link
Contributor

@josemenvegsngular josemenvegsngular Apr 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A doubt: won't it be better to group the constant values depending on their objective?
I'm thinking of an enum group with all the types (integer, double, float, ... as we get in UNION) instead of getting a big group with a constant mix.

Anyway, I think that, at least in this file, there is a style issue in line 15 (double space between static and final)

Copy link
Member

@AdrianLagartera AdrianLagartera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the way you put some type of variable to following one way, of course if you want use var and String its a good idea for example if you use the var in a lambda or for a generic object, but if two methods have a very similar code, try to replicate the same way as I mention in previous comments

And please fix the tests, I think you change a lot of classes and only I see one test change, be sure about you test properly the new changes

Comment on lines 27 to 31
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.19</version>
</dependency>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think add a new dependency just to use the RequestMethod.values method which only return a list of enums with the http operations not the best solution, I could suggest to you create your own class enum for this purpose.

And by the way be careful when you add a new dependency, because in this case this version of spring-web have a known vulnerability

Comment on lines 84 to 94
var typeMap = "";
if (mapSchema.get(ADDITIONAL_PROPERTIES)==null) return null;
final var mapNode = mapSchema.get(ADDITIONAL_PROPERTIES);
final var mapValueType = mapNode.findPath(TYPE);
typeMap = getCollectionType(mapNode, mapValueType, prefix, suffix);
return typeMap;
}

public static String getCollectionType(final JsonNode mapNode, final JsonNode mapValueType, final String prefix, final String suffix) {
String typeMap = null;
if ((checkTextValueNotNull(mapValueType))&&(!mapValueType.textValue().contains("#"))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why at the beginning of this method use var, and in the next one use String, checking other parts of the code you did the same, I think you should take a way to choose var or String to avoid problems with readability, because looks like each one with a different type of variable could be uses for different purpose

import com.sngular.api.generator.plugin.openapi.model.GlobalObject;
import com.sngular.api.generator.plugin.openapi.model.PathObject;
import com.sngular.api.generator.plugin.openapi.model.SchemaObject;
import com.sngular.api.generator.plugin.openapi.model.*;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this * and import only those classes that you really need.


import java.util.*;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you have another * on a import, so I tell you the same as my previous comment.

final String itemType = Objects.nonNull(arraySchema.getItems().get$ref()) ? getRef(arraySchema.getItems(), specFile) : arraySchema.getItems().getType();
} else if ((ARRAY.equalsIgnoreCase(getTextValue(schema,TYPE))) &&(checkNotEmpty(schema,ITEMS))){
final String itemType = Objects.nonNull(schema.get(ITEMS).get(REF)) ? MapperUtilCommon.getRef(schema.get(ITEMS), specFile.getModelNamePrefix(),
specFile.getModelNameSuffix()) : getTextValue(schema.get(ITEMS),TYPE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here you have some issues related with the style, so I suggest you to run the autoformatter.

@5uso-sng 5uso-sng requested review from janDuinRod and removed request for janDuinRod April 12, 2023 08:20
Comment on lines 66 to 71
return null;
}
public static boolean checkTextValueNotNull(JsonNode schema){
return (schema != null && schema.textValue()!= null && !schema.isNull());
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure you are using the OSS style rules

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import static com.sngular.api.generator.plugin.commonApi.Constants.*;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid * imports


public class OpenApiGenerator {

public static final String AUTHENTICATION = "Authentication";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this shouldn't be private?

Comment on lines 66 to 70
public static final String SERVERS = "servers";

public static final String SECURITY_SCHEMES = "securitySchemes";

public static final String SECURITY = "security";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said on my last comment shouldn't this be private as well?

Comment on lines 257 to 268
File dir = path.toFile();
boolean created = dir.mkdirs();
if (!created && !dir.isDirectory()) {
throw new RuntimeException("Failed to create directory: " + dir);
}
path = path.resolve(convertPackageToTargetPath(fileSpecPackage, isModel));
}
if (!path.toFile().isDirectory()) {
path.toFile().mkdirs();
File dir = path.toFile();
if (!dir.isDirectory()) {
boolean created = dir.mkdirs();
if (!created) {
throw new RuntimeException("Failed to create directory: " + dir);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directories are created from a path in 2 different ways in the same function, also, the code is repeated multiple times, wouldn't it be better to extract it to a function?

Copy link
Contributor

@janDuinRod janDuinRod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please run the autoformater and checkstyle with the already existing conifgurations (styles folder), apart from fixing all the aforementioned issues.

Copy link
Contributor

@5uso-sng 5uso-sng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make sure to run the autoformatter, as well as checkstyle. There's a lot of indentation, spacing, and newline inconsistencies. Other style differences, such as the use of returns or final variables are pointed out by our checkstyle configuration.

Also, note that the integration tests aren't passing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file seems to be a duplicate, another copy already existed in the styles directory

Comment on lines 58 to 67
public static String getTextValue(JsonNode node, String field){
try{
if(checkTextValueNotNull(node.get(field)))
return node.get(field).textValue();
}
catch (StackOverflowError e){
return null;
}
return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a public function, it would probably be a good idea to annotate it as nullable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking... what would change if we do something like:

catch (StackOverflowError e){}
finally {
      return null;
    }
}

To avoid duplicating return null;

return typeArray;
}

public static boolean checkNotEmpty (JsonNode node, String ... fields){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameters of this function should be final

}

public static boolean checkNotEmpty (JsonNode node, String ... fields){
for (String field : fields.clone()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we cloning a varargs of an immutable type to iterate over it?


public static boolean checkNotEmpty (JsonNode node, String ... fields){
for (String field : fields.clone()) {
if (node == null || node.get(field) == null || node.get(field).toString().isEmpty() || (NULL.equalsIgnoreCase(node.get(field).toString())))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value of node doesn't change during the loop, so it would be better extracting the first check from the loop

public static boolean checkNotEmpty (JsonNode node, String ... fields){
for (String field : fields.clone()) {
if (node == null || node.get(field) == null || node.get(field).toString().isEmpty() || (NULL.equalsIgnoreCase(node.get(field).toString())))
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are discouraged from using return statements in the middle of functions

Comment on lines 195 to 197
} catch (IOException e) {
e.printStackTrace();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it safe to continue execution after this fails?

Comment on lines 124 to 125
private void processFile(final SpecFile specFile, final String filePathToSave) throws TemplateException, IOException {
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This try block has a way bigger scope than it should, especially since it's ignoring the exception. It's also strange to catch IOExceptions in a function that does throw IOException

Comment on lines 48 to 52
return API_KEY_AUTH;
} else if (type.equalsIgnoreCase(OAUTH_2)) {
return StringUtils.capitalize(OAUTH);
} else if (type.equalsIgnoreCase(HTTP)) {
return HTTP_BASIC_AUTH;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In these cases we typically store the value to return in a final variable that's uninitialized at the start of the function and set where these returns are, with a single return at the end of the function

}
if (Boolean.TRUE.equals(checkIfOperationIsNull(path.getValue().getPatch()))) {
operationObjects.add(createOperation(openAPI, path.getValue().getPatch(), "PATCH", specFile, globalObject, operationIdList));
for ( RequestMethod method: RequestMethod.values()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enum from Spring doesn't seem necessary. It would be preferrable to use our own, as to reduce the amount of dependencies

@5uso-sng
Copy link
Contributor

Oh, just noticed the version numbers will need to be updated. Make sure to do it not just in the engine pom, but in the maven and gradle plugins as well

} else {
mapValueType = arrayNode.get(REF);
}
typeArray = getCollectionType(arrayNode, mapValueType, prefix, suffix);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm looking this code and L.88 and I think that the condition can be moved inside getCollectionType method:

  • in both, the second parameter is obtained from the first parameter (in L.88 send always the TYPE but in L.116, it check if the TYPE is present?)
  • the issue is: does this method called from other parts of the code?
  • even inside the own method it checks if the second parameter contains # (as it would be a reference, instead of a type)


processOperation(fileParameter, ymlParentPath, entry, channel, operationId, channelPayload, totalSchemas);
}
handleMissingPublisherConsumer(fileParameter, channel, operationId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be there is a reason, but just with this code I have a doubt:
If operationId = getOperationId(channel) and channelPayload = getChannelPayload(channel) why in handleMissingPublisherConsumer and processOperation pass operationId and channelPayload as arguments when we can obtain their values through channel (which is also an argument)?

@jemacineiras jemacineiras force-pushed the 160-scs-multiapi-plugin-homogenize-code-generation-in-openapi-and-asyncapi branch from e10f393 to 04ef68c Compare May 18, 2023 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[SCS-MultiApi-Plugin]: Homogenize code generation in openApi and AsyncApi
8 participants