Skip to content

Commit

Permalink
Merge pull request #367 from Ladicek/protobuf-schema-evolution
Browse files Browse the repository at this point in the history
Introduce mechanism for specifying protobuf field numbers
  • Loading branch information
vietj authored Oct 20, 2023
2 parents db1b42e + df2886d commit d44a385
Show file tree
Hide file tree
Showing 29 changed files with 893 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
import io.vertx.codegen.type.TypeMirrorFactory;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -85,7 +87,12 @@ public boolean process() {
enumItemDeprecatedDesc = new Text(Helper.normalizeWhitespaces(methodDeprecatedTag.get().getValue())).map(Token.tagMapper(elementUtils, typeUtils, modelElt));
}
}
return new EnumValueInfo(elt.getSimpleName().toString(), doc, elt.getAnnotation(Deprecated.class) != null, enumItemDeprecatedDesc);
List<? extends AnnotationMirror> annotationMirrors = elt.getAnnotationMirrors();
List<AnnotationValueInfo> annotationValueInfos = new ArrayList<>();
if (annotationMirrors != null) {
annotationMirrors.stream().map(annotationValueInfoFactory::processAnnotation).forEach(annotationValueInfos::add);
}
return new EnumValueInfo(elt.getSimpleName().toString(), doc, elt.getAnnotation(Deprecated.class) != null, enumItemDeprecatedDesc, annotationValueInfos);
}).
collect(Collectors.toList());
if (values.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

import io.vertx.codegen.doc.Doc;
import io.vertx.codegen.doc.Text;
import io.vertx.codegen.type.AnnotationValueInfo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* The value (member) of an enumeration model.
Expand All @@ -14,12 +20,14 @@ public class EnumValueInfo {
private final Doc doc;
private final boolean deprecated;
private final Text deprecatedDesc;
private final Map<String, AnnotationValueInfo> annotations;

public EnumValueInfo(String identifier, Doc doc, boolean deprecated, Text deprecatedDesc) {
public EnumValueInfo(String identifier, Doc doc, boolean deprecated, Text deprecatedDesc, List<AnnotationValueInfo> annotations) {
this.identifier = identifier;
this.doc = doc;
this.deprecated = deprecated;
this.deprecatedDesc = deprecatedDesc;
this.annotations = annotations.stream().collect(HashMap::new, (m, a) -> m.put(a.getName(), a), HashMap::putAll);
}

/**
Expand Down Expand Up @@ -48,4 +56,20 @@ public boolean isDeprecated() {
public Text getDeprecatedDesc() {
return deprecatedDesc;
}

/**
* @return the list of {@link AnnotationValueInfo} for this enum value
*/
public List<AnnotationValueInfo> getAnnotations() {
return new ArrayList<>(annotations.values());
}

/**
* @param annotationName fully qualified name of an annotation type
* @return {@link AnnotationValueInfo} for an annotation of given type present on this enum value,
* or {@code null} if an annotation of given type is not present on this enum value
*/
public AnnotationValueInfo getAnnotation(String annotationName) {
return annotations.get(annotationName);
}
}
12 changes: 12 additions & 0 deletions vertx-codegen-processor/src/main/java/io/vertx/codegen/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import io.vertx.codegen.type.TypeInfo;

import javax.lang.model.element.Element;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
* @author <a href="mailto:[email protected]">Julien Viet</a>
Expand All @@ -26,6 +28,16 @@ default List<AnnotationValueInfo> getAnnotations() {
return Collections.emptyList();
}

default Optional<AnnotationValueInfo> getAnnotation(Class<? extends Annotation> annotationType) {
String annotationName = annotationType.getName();
for (AnnotationValueInfo annotation : getAnnotations()) {
if (annotation.getName().equals(annotationName)) {
return Optional.of(annotation);
}
}
return Optional.empty();
}

default Map<String, Object> getVars() {
HashMap<String, Object> vars = new HashMap<>();
vars.put("helper", new Helper());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ public List<AnnotationValueInfo> getAnnotations() {
return new ArrayList<>(annotations.values());
}

/**
* @param annotationName fully qualified name of an annotation type
* @return {@link AnnotationValueInfo} for an annotation of given type present on this property,
* or {@code null} if an annotation of given type is not present on this property
*/
public AnnotationValueInfo getAnnotation(String annotationName) {
return annotations.get(annotationName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import io.vertx.codegen.GenException;
import io.vertx.codegen.PropertyInfo;
import io.vertx.codegen.PropertyKind;
import io.vertx.codegen.annotations.DataObject;
import io.vertx.codegen.annotations.VertxGen;
import io.vertx.codegen.doc.Doc;
import io.vertx.codegen.type.*;
import io.vertx.core.json.JsonArray;
Expand Down Expand Up @@ -672,7 +674,11 @@ public void testToJson() throws Exception {
public void testAnnotatedObject() throws Exception {
DataObjectModel model = new GeneratorHelper().generateDataObject(AnnotatedDataObject.class);
assertEquals(2, model.getAnnotations().size());
assertEquals(EmptyAnnotation.class.getSimpleName(),model.getAnnotations().get(1).getSimpleName());
assertEquals(DataObject.class.getSimpleName(), model.getAnnotations().get(0).getSimpleName());
assertEquals(EmptyAnnotation.class.getSimpleName(), model.getAnnotations().get(1).getSimpleName());
assertTrue(model.getAnnotation(DataObject.class).isPresent());
assertTrue(model.getAnnotation(EmptyAnnotation.class).isPresent());
assertFalse(model.getAnnotation(Deprecated.class).isPresent());
}

@Test
Expand Down Expand Up @@ -893,9 +899,12 @@ public void testDataObjectWithAnnotations() throws Exception {
PropertyInfo idModel = model.getPropertyMap().get("id");
assertEquals(1, idModel.getAnnotations().size());
assertNotNull(idModel.getAnnotation(SomeAnnotation.class.getName()).getName());
assertEquals(SomeAnnotation.class.getName(), idModel.getAnnotation(SomeAnnotation.class.getName()).getName());
assertEquals(2, idModel.getAnnotation(SomeAnnotation.class.getName()).getMember("value"));
PropertyInfo fieldWithMethodAnnotationModel = model.getPropertyMap().get("fieldWithMethodAnnotation");
assertEquals(2, fieldWithMethodAnnotationModel.getAnnotations().size());
assertNotNull(fieldWithMethodAnnotationModel.getAnnotation(SomeAnnotation.class.getName()).getName());
assertEquals(3, fieldWithMethodAnnotationModel.getAnnotation(SomeAnnotation.class.getName()).getMember("value"));
assertNotNull(fieldWithMethodAnnotationModel.getAnnotation(SomeMethodAnnotation.class.getName()).getName());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.vertx.test.codegen.testapi.jsonmapper.WithMyCustomEnumWithMapper;
import io.vertx.test.codegen.testenum.EnumAsParam;
import io.vertx.test.codegen.testenum.InvalidEmptyEnum;
import io.vertx.test.codegen.testenum.SomeAnnotation;
import io.vertx.test.codegen.testenum.ValidEnum;
import org.junit.Test;

Expand All @@ -31,6 +32,9 @@ public void testEnum() throws Exception {
assertEquals(Arrays.asList("RED doc", "GREEN doc", "BLUE doc"), model.getValues().stream().
map(e -> e.getDoc().toString()).
collect(Collectors.toList()));
assertEquals(Arrays.asList("red", "green", "blue"), model.getValues().stream()
.map(e -> e.getAnnotation(SomeAnnotation.class.getName()).getMember("value"))
.collect(Collectors.toList()));
assertEquals("enum", model.getKind());
assertEquals("ValidEnum doc", model.getDoc().toString());
assertEquals(ValidEnum.class.getName(), model.getFqn());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
import io.vertx.codegen.annotations.DataObject;
import io.vertx.core.json.JsonObject;

@SomeAnnotation
@SomeAnnotation(1)
@DataObject(generateConverter = true)
public class DataObjectWithAnnotatedField {

@SomeAnnotation
@SomeAnnotation(2)
private Long id;

private String name;

private String author;

@SomeAnnotation
@SomeAnnotation(3)
private String fieldWithMethodAnnotation;

// Mandatory for JPA entities
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
*/
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.TYPE})
public @interface SomeAnnotation {
int value();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.vertx.test.codegen.testenum;

public @interface SomeAnnotation {
String value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
public enum ValidEnum {

/**RED doc*/
@SomeAnnotation("red")
RED,

/**GREEN doc*/
@SomeAnnotation("green")
GREEN,

/**BLUE doc*/
@SomeAnnotation("blue")
BLUE

}
14 changes: 14 additions & 0 deletions vertx-codegen-protobuf/src/converters/generated/dataobjects.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,26 @@ message Address {
float latitude = 3;
}

message Book {
reserved 2;
reserved "title";
string name = 1;
string author = 3;
string isbn = 10;
string genre = 20;
}

enum EnumType {
A = 0;
B = 1;
C = 2;
}

message Person {
string name = 2;
int32 age = 4;
}

message RecursiveItem {
string id = 1;
RecursiveItem childA = 2;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package io.vertx.test.codegen.converter;

import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.CodedInputStream;
import java.io.IOException;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
import io.vertx.core.json.JsonObject;
import io.vertx.codegen.protobuf.utils.ExpandableIntArray;
import io.vertx.codegen.protobuf.converters.*;

public class BookProtoConverter {

public static void fromProto(CodedInputStream input, Book obj) throws IOException {
int tag;
while ((tag = input.readTag()) != 0) {
switch (tag) {
case 10: {
obj.setName(input.readString());
break;
}
case 26: {
obj.setAuthor(input.readString());
break;
}
case 82: {
obj.setIsbn(input.readString());
break;
}
case 162: {
obj.setGenre(input.readString());
break;
}
}
}
}

public static void toProto(Book obj, CodedOutputStream output) throws IOException {
ExpandableIntArray cache = new ExpandableIntArray(16);
BookProtoConverter.computeSize(obj, cache, 0);
BookProtoConverter.toProto(obj, output, cache, 0);
}

public static int toProto(Book obj, CodedOutputStream output, ExpandableIntArray cache, int index) throws IOException {
index = index + 1;
if (obj.getName() != null) {
output.writeString(1, obj.getName());
}
if (obj.getAuthor() != null) {
output.writeString(3, obj.getAuthor());
}
if (obj.getIsbn() != null) {
output.writeString(10, obj.getIsbn());
}
if (obj.getGenre() != null) {
output.writeString(20, obj.getGenre());
}
return index;
}

public static int computeSize(Book obj) {
ExpandableIntArray cache = new ExpandableIntArray(16);
BookProtoConverter.computeSize(obj, cache, 0);
return cache.get(0);
}

public static int computeSize(Book obj, ExpandableIntArray cache, final int baseIndex) {
int size = 0;
int index = baseIndex + 1;
if (obj.getName() != null) {
size += CodedOutputStream.computeStringSize(1, obj.getName());
}
if (obj.getAuthor() != null) {
size += CodedOutputStream.computeStringSize(3, obj.getAuthor());
}
if (obj.getIsbn() != null) {
size += CodedOutputStream.computeStringSize(10, obj.getIsbn());
}
if (obj.getGenre() != null) {
size += CodedOutputStream.computeStringSize(20, obj.getGenre());
}
cache.set(baseIndex, size);
return index;
}

}
Loading

0 comments on commit d44a385

Please sign in to comment.