@Override protected void validateConstructors() { if (constructorInjections.size() > 1) { metadataErrors.addError("Multiple constructors are annotated with @ThriftConstructor ", constructorInjections); } }
protected final String extractFieldName(short id, Collection<FieldMetadata> fields) { // get the names used by these fields Set<String> names = ImmutableSet.copyOf(filter(transform(fields, getThriftFieldName()), notNull())); String name; if (!names.isEmpty()) { if (names.size() > 1) { metadataErrors.addWarning("Thrift class %s field %s has multiple names %s", structName, id, names); } name = names.iterator().next(); } else { // pick a name for this field name = Iterables.find(transform(fields, extractThriftFieldName()), notNull()); } return name; }
@Test public void testMulitpleRequiredness() { ThriftStructMetadataBuilder builder = new ThriftStructMetadataBuilder(new ThriftCatalog(), MultipleRequiredness.class); MetadataErrors metadataErrors = builder.getMetadataErrors(); assertThat(metadataErrors.getErrors()) .as("metadata errors") .hasSize(1); assertThat(metadataErrors.getWarnings()) .as("metadata warnings") .isEmpty(); assertThat(metadataErrors.getErrors().get(0).getMessage()) .as("error message") .containsIgnoringCase("multiple requiredness"); }
@Override public ThriftStructMetadata build() { // this code assumes that metadata is clean metadataErrors.throwIfHasErrors(); // builder constructor injection ThriftMethodInjection builderMethodInjection = buildBuilderConstructorInjections(); // constructor injection (or factory method for builder) ThriftConstructorInjection constructorInjection = buildConstructorInjection(); // fields injections Iterable<ThriftFieldMetadata> fieldsMetadata = buildFieldInjections(); // methods injections List<ThriftMethodInjection> methodInjections = buildMethodInjections(); return new ThriftStructMetadata( structName, structType, builderType, MetadataType.UNION, Optional.fromNullable(builderMethodInjection), ImmutableList.copyOf(documentation), ImmutableList.copyOf(fieldsMetadata), Optional.fromNullable(constructorInjection), methodInjections ); }
private <T extends AbstractThriftMetadataBuilder> ThriftStructMetadata buildMetadata( Class<?> structClass, Class<T> metadataBuilderType) throws Exception { ThriftCatalog catalog = new ThriftCatalog(); AbstractThriftMetadataBuilder builder = metadataBuilderType.getConstructor(ThriftCatalog.class, Type.class) .newInstance(catalog, structClass); assertNotNull(builder); assertNotNull(builder.getMetadataErrors()); builder.getMetadataErrors().throwIfHasErrors(); assertEquals(builder.getMetadataErrors().getWarnings().size(), 0); return builder.build(); }
protected AbstractThriftMetadataBuilder(ThriftCatalog catalog, Type structType) { this.catalog = checkNotNull(catalog, "catalog is null"); this.structType = checkNotNull(structType, "structType is null"); this.metadataErrors = new MetadataErrors(catalog.getMonitor()); // assign the struct name from the annotation or from the Java class structName = extractName(); // get the builder type from the annotation or from the Java class builderType = extractBuilderType(); // grab any documentation from the annotation or saved JavaDocs documentation = ThriftCatalog.getThriftDocumentation(getStructClass()); // extract all of the annotated constructor and report an error if // there is more than one or none // also extract thrift fields from the annotated parameters and verify extractFromConstructors(); // extract thrift fields from the annotated fields and verify extractFromFields(); // extract thrift fields from the annotated methods (and parameters) and verify extractFromMethods(); }
@Test public void testUnsupportedType() throws Exception { ThriftStructMetadataBuilder builder = new ThriftStructMetadataBuilder(new ThriftCatalog(), UnsupportedJavaType.class); MetadataErrors metadataErrors = builder.getMetadataErrors(); assertThat(metadataErrors.getErrors()) .as("metadata errors") .hasSize(1); assertThat(metadataErrors.getWarnings()) .as("metadata warnings") .isEmpty(); assertThat(metadataErrors.getErrors().get(0).getMessage()) .as("error message") .containsIgnoringCase("not a supported Java type"); }
@Override public ThriftStructMetadata build() { // this code assumes that metadata is clean metadataErrors.throwIfHasErrors(); // builder constructor injection ThriftMethodInjection builderMethodInjection = buildBuilderConstructorInjections(); // constructor injection (or factory method for builder) ThriftConstructorInjection constructorInjections = buildConstructorInjection(); // fields injections Iterable<ThriftFieldMetadata> fieldsMetadata = buildFieldInjections(); // methods injections List<ThriftMethodInjection> methodInjections = buildMethodInjections(); return new ThriftStructMetadata( structName, structType, builderType, MetadataType.STRUCT, Optional.fromNullable(builderMethodInjection), ImmutableList.copyOf(documentation), ImmutableList.copyOf(fieldsMetadata), Optional.of(constructorInjections), methodInjections ); }
private ThriftStructMetadata testMetadataBuild(Class<?> structClass, int expectedConstructorParameters, int expectedMethodInjections) { ThriftCatalog catalog = new ThriftCatalog(); ThriftUnionMetadataBuilder builder = new ThriftUnionMetadataBuilder(catalog, structClass); assertNotNull(builder); assertNotNull(builder.getMetadataErrors()); builder.getMetadataErrors().throwIfHasErrors(); assertEquals(builder.getMetadataErrors().getWarnings().size(), 0); ThriftStructMetadata metadata = builder.build(); assertNotNull(metadata); assertEquals(MetadataType.UNION, metadata.getMetadataType()); verifyField(metadata, 1, "stringValue"); verifyField(metadata, 2, "longValue"); verifyField(metadata, 3, "fruitValue"); if (expectedConstructorParameters == 0) { assertTrue(metadata.getConstructorInjection().isPresent()); ThriftConstructorInjection constructorInjection = metadata.getConstructorInjection().get(); assertEquals(constructorInjection.getParameters().size(), 0); } else { for (ThriftFieldMetadata fieldMetadata : metadata.getFields(FieldKind.THRIFT_FIELD)) { assertTrue(fieldMetadata.getConstructorInjection().isPresent()); assertEquals(fieldMetadata.getConstructorInjection().get().getParameters().size(), expectedConstructorParameters); } } assertEquals(metadata.getMethodInjections().size(), expectedMethodInjections); return metadata; }
protected AbstractThriftMetadataBuilder(ThriftCatalog catalog, Type structType) { this.catalog = checkNotNull(catalog, "catalog is null"); this.structType = checkNotNull(structType, "structType is null"); this.metadataErrors = new MetadataErrors(catalog.getMonitor()); // assign the struct name from the annotation or from the Java class structName = extractName(); // get the builder type from the annotation or from the Java class builderType = extractBuilderType(); // grab any documentation from the annotation or saved JavaDocs documentation = ThriftCatalog.getThriftDocumentation(getStructClass()); // extract all of the annotated constructor and report an error if // there is more than one or none // also extract thrift fields from the annotated parameters and verify extractFromConstructors(); // extract thrift fields from the annotated fields and verify extractFromFields(); // extract thrift fields from the annotated methods (and parameters) and verify extractFromMethods(); }
@Override protected void validateConstructors() { if (constructorInjections.size() > 1) { metadataErrors.addError("Multiple constructors are annotated with @ThriftConstructor ", constructorInjections); } }
@Test public void testMultipleIds() throws Exception { ThriftStructMetadataBuilder builder = new ThriftStructMetadataBuilder(new ThriftCatalog(), MultipleIds.class); MetadataErrors metadataErrors = builder.getMetadataErrors(); assertThat(metadataErrors.getErrors()) .as("metadata errors") .hasSize(1); assertThat(metadataErrors.getWarnings()) .as("metadata warnings") .isEmpty(); assertThat(metadataErrors.getErrors().get(0).getMessage()) .as("error message") .containsIgnoringCase("multiple ids"); }
@Override public ThriftStructMetadata build() { // this code assumes that metadata is clean metadataErrors.throwIfHasErrors(); // builder constructor injection ThriftMethodInjection builderMethodInjection = buildBuilderConstructorInjections(); // constructor injection (or factory method for builder) ThriftConstructorInjection constructorInjection = buildConstructorInjection(); // fields injections Iterable<ThriftFieldMetadata> fieldsMetadata = buildFieldInjections(); // methods injections List<ThriftMethodInjection> methodInjections = buildMethodInjections(); return new ThriftStructMetadata( structName, extractStructIdlAnnotations(), structType, builderType, MetadataType.UNION, Optional.fromNullable(builderMethodInjection), ImmutableList.copyOf(documentation), ImmutableList.copyOf(fieldsMetadata), Optional.fromNullable(constructorInjection), methodInjections ); }
protected final String extractFieldName(short id, Collection<FieldMetadata> fields) { // get the names used by these fields Set<String> names = ImmutableSet.copyOf(filter(transform(fields, getThriftFieldName()), notNull())); String name; if (!names.isEmpty()) { if (names.size() > 1) { metadataErrors.addWarning("Thrift class %s field %s has multiple names %s", structName, id, names); } name = names.iterator().next(); } else { // pick a name for this field name = Iterables.find(transform(fields, extractThriftFieldName()), notNull()); } return name; }
protected final boolean extractFieldIsLegacyId(short id, String fieldName, Collection<FieldMetadata> fields) { Set<Boolean> isLegacyIds = ImmutableSet.copyOf(Optional.presentInstances(transform(fields, getThriftFieldIsLegacyId()))); if (isLegacyIds.size() > 1) { metadataErrors.addError("Thrift class '%s' field '%s' has both isLegacyId=true and isLegacyId=false", structName, fieldName); } if (id < 0) { if (! isLegacyIds.contains(true)) { metadataErrors.addError("Thrift class '%s' field '%s' has a negative field id but not isLegacyId=true", structName, fieldName); } } else { if (isLegacyIds.contains(true)) { metadataErrors.addError("Thrift class '%s' field '%s' has isLegacyId=true but not a negative field id", structName, fieldName); } } return id < 0; }
@Test public void testMultipleTypes() throws Exception { ThriftUnionMetadataBuilder builder = new ThriftUnionMetadataBuilder(new ThriftCatalog(), MultipleTypes.class); MetadataErrors metadataErrors = builder.getMetadataErrors(); assertThat(metadataErrors.getErrors()) .as("metadata errors") .hasSize(1); assertThat(metadataErrors.getWarnings()) .as("metadata warnings") .isEmpty(); assertThat(metadataErrors.getErrors().get(0).getMessage()) .as("error message") .containsIgnoringCase("multiple types"); }
@Override public ThriftStructMetadata build() { // this code assumes that metadata is clean metadataErrors.throwIfHasErrors(); // builder constructor injection ThriftMethodInjection builderMethodInjection = buildBuilderConstructorInjections(); // constructor injection (or factory method for builder) ThriftConstructorInjection constructorInjections = buildConstructorInjection(); // fields injections Iterable<ThriftFieldMetadata> fieldsMetadata = buildFieldInjections(); // methods injections List<ThriftMethodInjection> methodInjections = buildMethodInjections(); return new ThriftStructMetadata( structName, extractStructIdlAnnotations(), structType, builderType, MetadataType.STRUCT, Optional.fromNullable(builderMethodInjection), ImmutableList.copyOf(documentation), ImmutableList.copyOf(fieldsMetadata), Optional.of(constructorInjections), methodInjections ); }
protected final void extractFromConstructors() { if (builderType == null) { // struct class must have a valid constructor addConstructors(structType); } else { // builder class must have a valid constructor addConstructors(builderType); // builder class must have a build method annotated with @ThriftConstructor addBuilderMethods(); // verify struct class does not have @ThriftConstructors for (Constructor<?> constructor : getStructClass().getConstructors()) { if (constructor.isAnnotationPresent(ThriftConstructor.class)) { metadataErrors.addWarning("Thrift class '%s' has a builder class, but constructor '%s' annotated with @ThriftConstructor", getStructClass().getName(), constructor); } } } }
protected final void verifyClass(Class<? extends Annotation> annotation) { String annotationName = annotation.getSimpleName(); String structClassName = getStructClass().getName(); // Verify struct class is public and final if (!Modifier.isPublic(getStructClass().getModifiers())) { metadataErrors.addError("%s class '%s' is not public", annotationName, structClassName); } if (!getStructClass().isAnnotationPresent(annotation)) { metadataErrors.addError("%s class '%s' does not have a @%s annotation", annotationName, structClassName, annotationName); } }
@Test public void testNoId() throws Exception { ThriftStructMetadataBuilder builder = new ThriftStructMetadataBuilder(new ThriftCatalog(), NoId.class); MetadataErrors metadataErrors = builder.getMetadataErrors(); assertThat(metadataErrors.getErrors()) .as("metadata errors") .hasSize(1); assertThat(metadataErrors.getWarnings()) .as("metadata warnings") .isEmpty(); assertThat(metadataErrors.getErrors().get(0).getMessage()) .as("error message") .containsIgnoringCase("not have an id"); }