Skip to content
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
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<javaparser.version>3.26.1</javaparser.version>
<junit.version>5.10.3</junit.version>
<mockito.version>5.12.0 </mockito.version>
<swagger.version>2.2.22</swagger.version>
<swagger.version>2.2.36</swagger.version>
<cxf.version>4.0.3</cxf.version>
<jackson.version>2.17.1</jackson.version>
<unknow-sax.version>0.0.3</unknow-sax.version>
Expand Down Expand Up @@ -349,7 +349,7 @@
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<artifactId>swagger-annotations-jakarta</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
Expand Down
2 changes: 1 addition & 1 deletion unknow-server-maven/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@

<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<artifactId>swagger-annotations-jakarta</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,22 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.maven.plugin.MojoExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;

import io.swagger.v3.oas.annotations.tags.Tags;
import io.swagger.v3.oas.models.OpenAPI;
Expand All @@ -41,6 +48,7 @@
import unknow.server.maven.jaxrs.JaxrsParam.JaxrsBeanParam.JaxrsBeanFieldParam;
import unknow.server.maven.jaxrs.JaxrsParam.JaxrsBodyParam;
import unknow.server.maven.jaxrs.JaxrsParam.JaxrsCookieParam;
import unknow.server.maven.jaxrs.JaxrsParam.JaxrsFormParam;
import unknow.server.maven.jaxrs.JaxrsParam.JaxrsHeaderParam;
import unknow.server.maven.jaxrs.JaxrsParam.JaxrsMatrixParam;
import unknow.server.maven.jaxrs.JaxrsParam.JaxrsPathParam;
Expand Down Expand Up @@ -134,9 +142,10 @@ private static Schema<?> getDefault(String n) {
private final Map<String, Schema> schemas = new HashMap<>();

public void build(OpenAPI spec, JaxrsModel model, String file) throws MojoExecutionException {
SimpleModule module = new SimpleModule().setSerializerModifier(new IgnoreOpenapiField());

ObjectMapper m = new ObjectMapper().enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING).disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.setDefaultPropertyInclusion(Include.NON_EMPTY);
.setDefaultPropertyInclusion(Include.NON_EMPTY).registerModule(module);
Path path = java.nio.file.Paths.get(file);
try {
Files.createDirectories(path.getParent());
Expand Down Expand Up @@ -172,9 +181,6 @@ private OpenAPI build(OpenAPI spec, JaxrsModel model) {
o.setTags(tags);
}

ApiResponses responses = new ApiResponses();
o.setResponses(responses);

if (a != null) {
a.member("tags").filter(v -> v.isSet()).map(v -> v.asArrayLiteral()).filter(v -> v.length > 0).ifPresent(v -> o.setTags(Arrays.asList(v)));
a.member("summary").filter(v -> v.isSet()).map(v -> v.asLiteral()).filter(v -> !v.isEmpty()).ifPresent(v -> o.setSummary(v));
Expand All @@ -187,12 +193,13 @@ private OpenAPI build(OpenAPI spec, JaxrsModel model) {
// TODO externalDocs, responses, security, servers, extensions
}

if (responses.isEmpty() && !m.m.type().isVoid()) {
if (!m.m.type().isVoid()) {
Content c = new Content();
for (String s : m.produce)
c.addMediaType(s, new MediaType().schema(schema(m.m.type())));
responses.addApiResponse("default", new ApiResponse().content(c));
}
o.setResponses(new ApiResponses().addApiResponse("default", new ApiResponse().description("default").content(c)));
} else
o.setResponses(new ApiResponses().addApiResponse("default", new ApiResponse().description("empty")));

for (JaxrsParam<?> param : m.params)
addParameters(o, param);
Expand All @@ -215,16 +222,24 @@ private void addParameters(Operation o, JaxrsParam<?> param) {
}

if (param instanceof JaxrsBodyParam) {
MediaType mdi = new MediaType();
mdi.examples(null);
mdi.schema(schema(param.type));
MediaType mdi = new MediaType().schema(schema(param.type));
Content content = new Content();
content.addMediaType("*/*", mdi);
o.setRequestBody(new RequestBody().content(content));
return;
}

Parameter p = new Parameter().name(param.value).schema(schema(param.type));
Optional<AnnotationModel> annotation = param.p.annotation(io.swagger.v3.oas.annotations.media.Schema.class);
if (param instanceof JaxrsFormParam) {
RequestBody b = o.getRequestBody();
if (b == null)
o.setRequestBody(b = new RequestBody().content(new Content()));
MediaType mdi = b.getContent().computeIfAbsent("application/x-www-form-urlencoded", k -> new MediaType().schema(new Schema<>().type("object")));
mdi.getSchema().addProperty(param.value, fillFrom(schema(param.type), annotation));
return;
}

Parameter p = new Parameter().name(param.value).schema(fillFrom(schema(param.type), annotation));
if (param instanceof JaxrsHeaderParam)
p.setIn("header");
else if (param instanceof JaxrsQueryParam)
Expand Down Expand Up @@ -303,16 +318,33 @@ private Schema<?> schema(TypeModel type) {
List<String> requied = new ArrayList<>();
s.type("object").setRequired(requied);
ClassModel c = type.asClass();
fillFrom(s, c.annotation(io.swagger.v3.oas.annotations.media.Schema.class));

for (FieldModel f : c.fields()) {
s.addProperty(f.name(), schema(f.type()));
if (f.isStatic() || f.isTransient())
continue;
Optional<AnnotationModel> a = f.annotation(io.swagger.v3.oas.annotations.media.Schema.class);
if (a.flatMap(o -> o.member("hidden")).map(o -> o.asBoolean()).orElse(false))
continue;

s.addProperty(f.name(), fillFrom(schema(f.type()), a));
// TODO add required value from jackson
}
// TODO exemple
}
return new Schema<>().$ref("#/components/schemas/" + n);
}

private Schema<?> fillFrom(Schema<?> s, Optional<AnnotationModel> annotation) {
if (annotation.isEmpty())
return s;
AnnotationModel a = annotation.get();
a.member("name").filter(v -> v.isSet()).ifPresent(v -> s.setName(v.asLiteral()));
a.member("title").filter(v -> v.isSet()).ifPresent(v -> s.setTitle(v.asLiteral()));
a.member("description").filter(v -> v.isSet()).ifPresent(v -> s.setDescription(v.asLiteral()));
return s;
}

/**
* @param p
* @param httpMethod
Expand Down Expand Up @@ -394,4 +426,22 @@ public static AnnotationModel[] findTags(ClassModel m) {
public Map<String, Schema> getSchemas() {
return schemas;
}

private static final class IgnoreOpenapiField extends BeanSerializerModifier {
private static final long serialVersionUID = 1L;
private static final Set<String> fieldsToIgnore = Set.of("exampleSetFlag");

@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {

// On filtre les propriétés à ignorer
List<BeanPropertyWriter> newProps = new ArrayList<>();
for (BeanPropertyWriter writer : beanProperties) {
if (!fieldsToIgnore.contains(writer.getName())) {
newProps.add(writer);
}
}
return newProps;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.MatrixParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
Expand All @@ -34,40 +35,44 @@

@GET
@Path("t")
public void t() throws InterruptedException {
@SuppressWarnings("unused")
public void t(@PathParam("q") String q) throws InterruptedException {
Thread.sleep(3000);
throw new NullPointerException("test");
}

@GET
@Path("q/{v}")
public void q() { // ok
@SuppressWarnings("unused")
public void q(@PathParam("q") String q, @PathParam("v") String v) { // ok
}

@GET
@POST
public void oneWay(@PathParam("q") String q, @BeanParam Bean bean) {
logger.info("oneWay>> q: '{}' bean: {}", q, bean);
}

@GET
@PUT
@Consumes({ "application/json", "application/x-ndjson" })
public Response response(@PathParam("q") String q, @BeanParam Bean bean) {
logger.info("response>> q: '{}' bean: {}", q, bean);
public Response response(@PathParam("q") String q, @FormParam("k") String k) {
logger.info("response>> q: '{}' bean: {}", q, k);
return Response.status(200).entity("echo").build();
}

@POST
@Consumes({ "application/x-protobuf", "application/json", "application/jsonl", "application/x-ndjson" })
@Produces({ "application/x-protobuf", "application/json", "application/jsonl", "application/x-ndjson" })
public Truc call(Truc truc) {
@SuppressWarnings("unused")
public Truc call(@PathParam("q") String q, Truc truc) {
return truc;
}

@POST
@Path("list")
@Consumes({ "application/x-protobuf", "application/json", "application/jsonl", "application/x-ndjson" })
@Produces({ "application/x-protobuf", "application/json", "application/jsonl", "application/x-ndjson" })
public Collection<Truc> list(Collection<Truc> truc) {
@SuppressWarnings("unused")
public Collection<Truc> list(@PathParam("q") String q, Collection<Truc> truc) {
return truc;
}

Expand Down