-
Notifications
You must be signed in to change notification settings - Fork 10
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
160 scs multiapi plugin homogenize code generation in openapi and asyncapi #200
Conversation
There was a problem hiding this 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!
This pull request hasn't been labeled as |
|
||
public final class Constants { | ||
|
||
public static final String INTEGER = "integer"; |
There was a problem hiding this comment.
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
)
There was a problem hiding this 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
multiapi-engine/pom.xml
Outdated
<dependency> | ||
<groupId>org.springframework</groupId> | ||
<artifactId>spring-web</artifactId> | ||
<version>5.3.19</version> | ||
</dependency> |
There was a problem hiding this comment.
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
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("#"))) { |
There was a problem hiding this comment.
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.*; |
There was a problem hiding this comment.
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.*; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
return null; | ||
} | ||
public static boolean checkTextValueNotNull(JsonNode schema){ | ||
return (schema != null && schema.textValue()!= null && !schema.isNull()); | ||
} | ||
|
There was a problem hiding this comment.
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.*; |
There was a problem hiding this comment.
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"; |
There was a problem hiding this comment.
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?
public static final String SERVERS = "servers"; | ||
|
||
public static final String SECURITY_SCHEMES = "securitySchemes"; | ||
|
||
public static final String SECURITY = "security"; |
There was a problem hiding this comment.
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?
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this 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.
There was a problem hiding this 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
OSS_style_idea.xml
Outdated
There was a problem hiding this comment.
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
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; | ||
} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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){ |
There was a problem hiding this comment.
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()) { |
There was a problem hiding this comment.
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()))) |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} |
There was a problem hiding this comment.
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?
private void processFile(final SpecFile specFile, final String filePathToSave) throws TemplateException, IOException { | ||
try { |
There was a problem hiding this comment.
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
return API_KEY_AUTH; | ||
} else if (type.equalsIgnoreCase(OAUTH_2)) { | ||
return StringUtils.capitalize(OAUTH); | ||
} else if (type.equalsIgnoreCase(HTTP)) { | ||
return HTTP_BASIC_AUTH; |
There was a problem hiding this comment.
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()) { |
There was a problem hiding this comment.
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
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); |
There was a problem hiding this comment.
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 theTYPE
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); |
There was a problem hiding this comment.
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)?
e10f393
to
04ef68c
Compare
Code refactoring to use JsonNode instead of swagger apis