ThriftDocServicePlugin implements DocServicePlugin { @VisibleForTesting @Nullable ServiceInfo newServiceInfo(Class<?> serviceClass, Iterable<EndpointInfo> endpoints, DocServiceFilter filter) { requireNonNull(serviceClass, "serviceClass"); final String name = serviceClass.getName(); final ClassLoader serviceClassLoader = serviceClass.getClassLoader(); final String interfaceClassName = name + "$Iface"; final Class<?> interfaceClass; try { interfaceClass = Class.forName(interfaceClassName, false, serviceClassLoader); } catch (ClassNotFoundException e) { throw new IllegalStateException("failed to find a class: " + interfaceClassName, e); } final Method[] methods = interfaceClass.getDeclaredMethods(); final List<MethodInfo> methodInfos = Arrays.stream(methods) .map(m -> newMethodInfo(m, endpoints, filter)) .filter(Objects::nonNull) .collect(toImmutableList()); if (methodInfos.isEmpty()) { return null; } return new ServiceInfo(name, methodInfos); }  @Override String name(); @Override Set<Class<? extends Service<?, ?>>> supportedServiceTypes(); @Override ServiceSpecification generateSpecification(Set<ServiceConfig> serviceConfigs,
                                                      DocServiceFilter filter); @VisibleForTesting ServiceSpecification generate(List<Entry> entries, DocServiceFilter filter); @Override Map<String, String> loadDocStrings(Set<ServiceConfig> serviceConfigs); @Override Set<Class<?>> supportedExampleRequestTypes(); @Override String guessServiceName(Object exampleRequest); @Override String guessServiceMethodName(Object exampleRequest); @Override String serializeExampleRequest(String serviceName, String methodName,
                                          Object exampleRequest);  }
@Test void testNewServiceInfo() { final ServiceInfo service = generator.newServiceInfo( FooService.class, ImmutableList.of(EndpointInfo.builder("*", "/foo") .fragment("a").defaultFormat(ThriftSerializationFormats.BINARY) .build(), EndpointInfo.builder("*", "/debug/foo") .fragment("b").defaultFormat(ThriftSerializationFormats.TEXT) .build()), (pluginName, serviceName, methodName) -> true); final Map<String, MethodInfo> methods = service.methods().stream().collect(toImmutableMap(MethodInfo::name, Function.identity())); assertThat(methods).hasSize(6); final MethodInfo bar1 = methods.get("bar1"); assertThat(bar1.parameters()).isEmpty(); assertThat(bar1.returnTypeSignature()).isEqualTo(TypeSignature.ofBase("void")); assertThat(bar1.exceptionTypeSignatures()).hasSize(1); assertThat(bar1.exampleRequests()).isEmpty(); assertThat(bar1.endpoints()).containsExactlyInAnyOrder( EndpointInfo.builder("*", "/foo") .fragment("a") .defaultFormat(ThriftSerializationFormats.BINARY) .build(), EndpointInfo.builder("*", "/debug/foo") .fragment("b") .defaultFormat(ThriftSerializationFormats.TEXT) .build()); final TypeSignature string = TypeSignature.ofBase("string"); final MethodInfo bar2 = methods.get("bar2"); assertThat(bar2.parameters()).isEmpty(); assertThat(bar2.returnTypeSignature()).isEqualTo(string); assertThat(bar2.exceptionTypeSignatures()).hasSize(1); assertThat(bar2.exampleRequests()).isEmpty(); final TypeSignature foo = TypeSignature.ofNamed(FooStruct.class); final MethodInfo bar3 = methods.get("bar3"); assertThat(bar3.parameters()).containsExactly( FieldInfo.of("intVal", TypeSignature.ofBase("i32")), FieldInfo.of("foo", foo)); assertThat(bar3.returnTypeSignature()).isEqualTo(foo); assertThat(bar3.exceptionTypeSignatures()).hasSize(1); assertThat(bar3.exampleRequests()).isEmpty(); final MethodInfo bar4 = methods.get("bar4"); assertThat(bar4.parameters()).containsExactly( FieldInfo.of("foos", TypeSignature.ofList(foo))); assertThat(bar4.returnTypeSignature()).isEqualTo(TypeSignature.ofList(foo)); assertThat(bar4.exceptionTypeSignatures()).hasSize(1); assertThat(bar4.exampleRequests()).isEmpty(); final MethodInfo bar5 = methods.get("bar5"); assertThat(bar5.parameters()).containsExactly( FieldInfo.of("foos", TypeSignature.ofMap(string, foo))); assertThat(bar5.returnTypeSignature()).isEqualTo(TypeSignature.ofMap(string, foo)); assertThat(bar5.exceptionTypeSignatures()).hasSize(1); assertThat(bar5.exampleRequests()).isEmpty(); final MethodInfo bar6 = methods.get("bar6"); assertThat(bar6.parameters()).containsExactly( FieldInfo.of("foo1", string), FieldInfo.of("foo2", TypeSignature.ofUnresolved("TypedefedStruct")), FieldInfo.of("foo3", TypeSignature.ofUnresolved("TypedefedEnum")), FieldInfo.of("foo4", TypeSignature.ofUnresolved("TypedefedMap")), FieldInfo.of("foo5", TypeSignature.ofUnresolved("TypedefedList")), FieldInfo.of("foo6", TypeSignature.ofUnresolved("TypedefedSet")), FieldInfo.of("foo7", TypeSignature.ofUnresolved("NestedTypedefedStructs")), FieldInfo.of("foo8", TypeSignature.ofList(TypeSignature.ofList( TypeSignature.ofUnresolved("TypedefedStruct"))))); assertThat(bar6.returnTypeSignature()).isEqualTo(TypeSignature.ofBase("void")); assertThat(bar6.exceptionTypeSignatures()).isEmpty(); assertThat(bar6.exampleRequests()).isEmpty(); final List<HttpHeaders> exampleHeaders = service.exampleHeaders(); assertThat(exampleHeaders).isEmpty(); }