Удалил SerializationUtils, добавил генератор спецификации api

This commit is contained in:
kirillius 2026-01-14 18:05:40 +03:00
parent 3ad2f762e0
commit 381fda5252
7 changed files with 143 additions and 13 deletions

View File

@ -9,7 +9,7 @@
<version>1.0.0.0</version> <version>1.0.0.0</version>
</parent> </parent>
<artifactId>api-generator</artifactId> <artifactId>api-spec-generator</artifactId>
<dependencies> <dependencies>
<dependency> <dependency>
@ -27,13 +27,18 @@
<version>3.1.0</version> <version>3.1.0</version>
<executions> <executions>
<execution> <execution>
<id>generate-js-client</id> <id>generate-spec</id>
<phase>generate-sources</phase> <phase>compile</phase>
<goals> <goals>
<goal>java</goal> <goal>java</goal>
</goals> </goals>
<configuration> <configuration>
<mainClass>ru.kirillius.XCP.ApiGenerator.JavascriptClientGenerator</mainClass> <mainClass>ru.kirillius.XCP.ApiGenerator.SpecGenerator</mainClass>
<arguments>
<argument>rpc/src/main/java</argument>
<argument>ru.kirillius.XCP.RPC.Services</argument>
<argument>target/generated-sources/api.spec.json</argument>
</arguments>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>

View File

@ -0,0 +1,125 @@
package ru.kirillius.XCP.ApiGenerator;
import lombok.SneakyThrows;
import ru.kirillius.XCP.RPC.JSONRPC.JsonRpcMethod;
import ru.kirillius.XCP.RPC.JSONRPC.JsonRpcService;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.node.ArrayNode;
import tools.jackson.databind.node.JsonNodeFactory;
import tools.jackson.databind.node.ObjectNode;
import java.io.*;
import java.util.Collection;
import java.util.Objects;
import java.util.regex.Pattern;
public class SpecGenerator {
/**
* Args:
* 1 - path to find classes
* 2 - search in package
* 3 - output spec file path
*
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
var generator = new SpecGenerator(
new File(args[0]),
args[1],
new File(args[2])
);
generator.generate();
generator.writeSpecs();
}
private final File scanDir;
private final String packageName;
private final File outputFile;
public SpecGenerator(File scanDir, String packageName, File outputFile) {
this.scanDir = scanDir;
this.packageName = packageName;
this.outputFile = outputFile;
}
private final ObjectNode specs = JsonNodeFactory.instance.objectNode();
@SneakyThrows
public void generate() {
specs.removeAll();
var scanPath = new File(scanDir, packageName.replaceAll(Pattern.quote("."), "/"));
for (var file : Objects.requireNonNull(scanPath.listFiles())) {
if (!file.getName().endsWith(".java") || file.getName().contains("$")) {
continue;
}
var className = packageName + '.' + file.getName();
className = className.substring(0, className.length() - ".java".length());
var cls = Class.forName(className);
if (!JsonRpcService.class.isAssignableFrom(cls)) {
continue;
}
var classSpecs = specs.putObject(cls.getSimpleName());
classSpecs.put("name", cls.getSimpleName());
var methods = classSpecs.putArray("methods");
for (var method : cls.getDeclaredMethods()) {
var descriptor = method.getAnnotation(JsonRpcMethod.class);
if (descriptor == null) {
continue;
}
var methodSpecs = methods.addObject();
methodSpecs.put("name", method.getName());
methodSpecs.put("description", descriptor.description());
methodSpecs.put("return", getTypeName(descriptor.returnType()));
methodSpecs.put("accessLevel", descriptor.accessLevel().name());
var params = methodSpecs.putArray("params");
for (var parameter : descriptor.parameters()) {
var paramSpecs = params.addObject();
paramSpecs.put("name", parameter.name());
paramSpecs.put("type", getTypeName(parameter.type()));
paramSpecs.put("description", parameter.description());
paramSpecs.put("optional", parameter.optional());
}
methodSpecs.put("return", getTypeName(descriptor.returnType()));
}
}
}
public void writeSpecs() throws IOException {
outputFile.getParentFile().mkdirs();
try (var stream = new FileOutputStream(outputFile)) {
var mapper = new ObjectMapper();
mapper.writerWithDefaultPrettyPrinter().writeValue(stream, specs);
}
}
private static String getTypeName(Class<?> type) {
if (type == null) return "unknown";
if (type == boolean.class) return "boolean";
if (type == int.class || type == long.class) return "number";
if (type == String.class) return "string";
if (type == void.class || type == Void.class) return "void";
if (type.isArray() || Collection.class.isAssignableFrom(type) || type == ArrayNode.class) {
return "Array";
}
if (JsonNode.class.isAssignableFrom(type)) {
return "Object";
}
return type.getSimpleName();
}
}

View File

@ -8,7 +8,7 @@ import org.hibernate.annotations.UuidGenerator;
import ru.kirillius.XCP.Commons.StreamHandler; import ru.kirillius.XCP.Commons.StreamHandler;
import ru.kirillius.XCP.Persistence.Entities.Group; import ru.kirillius.XCP.Persistence.Entities.Group;
import ru.kirillius.XCP.Persistence.*; import ru.kirillius.XCP.Persistence.*;
import ru.kirillius.XCP.Serialization.SerializationUtils; import tools.jackson.databind.node.JsonNodeFactory;
import tools.jackson.databind.node.ObjectNode; import tools.jackson.databind.node.ObjectNode;
import java.io.IOException; import java.io.IOException;
@ -157,7 +157,7 @@ public class GroupRepositoryImpl extends AbstractNodeRepository<Group> implement
@JsonProperty @JsonProperty
@Getter @Getter
@Setter @Setter
private ObjectNode properties = SerializationUtils.EmptyObject(); private ObjectNode properties = JsonNodeFactory.instance.objectNode();
@JsonIgnore @JsonIgnore
@ManyToMany(fetch = FetchType.EAGER) @ManyToMany(fetch = FetchType.EAGER)

View File

@ -11,9 +11,9 @@ import ru.kirillius.XCP.Persistence.Entities.Group;
import ru.kirillius.XCP.Persistence.Entities.Input; import ru.kirillius.XCP.Persistence.Entities.Input;
import ru.kirillius.XCP.Persistence.*; import ru.kirillius.XCP.Persistence.*;
import ru.kirillius.XCP.Serialization.PollSettingsConverter; import ru.kirillius.XCP.Serialization.PollSettingsConverter;
import ru.kirillius.XCP.Serialization.SerializationUtils;
import ru.kirillius.XCP.Serialization.ValueTransformationChainConverter; import ru.kirillius.XCP.Serialization.ValueTransformationChainConverter;
import tools.jackson.databind.annotation.JsonDeserialize; import tools.jackson.databind.annotation.JsonDeserialize;
import tools.jackson.databind.node.JsonNodeFactory;
import tools.jackson.databind.node.ObjectNode; import tools.jackson.databind.node.ObjectNode;
import java.util.HashSet; import java.util.HashSet;
@ -110,7 +110,7 @@ public class InputRepositoryImpl extends AbstractNodeRepository<Input> implement
@JsonProperty @JsonProperty
@Getter @Getter
@Setter @Setter
private ObjectNode properties = SerializationUtils.EmptyObject(); private ObjectNode properties = JsonNodeFactory.instance.objectNode();
@JsonIgnore @JsonIgnore
@ManyToMany(fetch = FetchType.EAGER) @ManyToMany(fetch = FetchType.EAGER)

View File

@ -9,8 +9,8 @@ import ru.kirillius.XCP.Data.ValueTransformationChain;
import ru.kirillius.XCP.Persistence.Entities.Group; import ru.kirillius.XCP.Persistence.Entities.Group;
import ru.kirillius.XCP.Persistence.Entities.Output; import ru.kirillius.XCP.Persistence.Entities.Output;
import ru.kirillius.XCP.Persistence.*; import ru.kirillius.XCP.Persistence.*;
import ru.kirillius.XCP.Serialization.SerializationUtils;
import ru.kirillius.XCP.Serialization.ValueTransformationChainConverter; import ru.kirillius.XCP.Serialization.ValueTransformationChainConverter;
import tools.jackson.databind.node.JsonNodeFactory;
import tools.jackson.databind.node.ObjectNode; import tools.jackson.databind.node.ObjectNode;
import java.util.HashSet; import java.util.HashSet;
@ -106,7 +106,7 @@ public class OutputRepositoryImpl extends AbstractNodeRepository<Output> impleme
@JsonProperty @JsonProperty
@Getter @Getter
@Setter @Setter
private ObjectNode properties = SerializationUtils.EmptyObject(); private ObjectNode properties = JsonNodeFactory.instance.objectNode();
@JsonIgnore @JsonIgnore
@ManyToMany(fetch = FetchType.EAGER) @ManyToMany(fetch = FetchType.EAGER)

View File

@ -12,7 +12,7 @@ import ru.kirillius.XCP.Persistence.Entities.User;
import ru.kirillius.XCP.Persistence.EntityImplementation; import ru.kirillius.XCP.Persistence.EntityImplementation;
import ru.kirillius.XCP.Persistence.RepositoryServiceImpl; import ru.kirillius.XCP.Persistence.RepositoryServiceImpl;
import ru.kirillius.XCP.Security.UserRole; import ru.kirillius.XCP.Security.UserRole;
import ru.kirillius.XCP.Serialization.SerializationUtils; import tools.jackson.databind.node.JsonNodeFactory;
import tools.jackson.databind.node.ObjectNode; import tools.jackson.databind.node.ObjectNode;
import java.io.IOException; import java.io.IOException;
@ -80,7 +80,7 @@ public class UserRepositoryImpl extends AbstractRepository<User> implements User
@Getter @Getter
@Setter @Setter
@JsonProperty @JsonProperty
private ObjectNode values = SerializationUtils.EmptyObject(); private ObjectNode values = JsonNodeFactory.instance.objectNode();
@Override @Override
public void setPassword(String password) { public void setPassword(String password) {

View File

@ -10,7 +10,7 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>api</module> <module>api</module>
<module>api-generator</module> <module>api-spec-generator</module>
<module>database</module> <module>database</module>
<module>core</module> <module>core</module>
<module>rpc</module> <module>rpc</module>