JsonConfigWriter implements ApiConfigWriter { @Override public Map<ApiKey, String> writeConfig(Iterable<? extends ApiConfig> configs) throws ApiConfigException { Multimap<ApiKey, ? extends ApiConfig> apisByKey = Multimaps.index(configs, new Function<ApiConfig, ApiKey>() { @Override public ApiKey apply(ApiConfig config) { return config.getApiKey(); } }); Map<ApiKey, String> results = Maps.newLinkedHashMap(); for (ApiKey apiKey : apisByKey.keySet()) { Collection<? extends ApiConfig> apiConfigs = apisByKey.get(apiKey); validator.validate(apiConfigs); results.put(apiKey, generateForApi(apiConfigs)); } return results; } JsonConfigWriter();  JsonConfigWriter(TypeLoader typeLoader, ApiConfigValidator validator); @Override Map<ApiKey, String> writeConfig(Iterable<? extends ApiConfig> configs); @Override String getFileExtension(); static final String MAP_SCHEMA_NAME; static final String ANY_SCHEMA_NAME; }
@Test public void writeConfigWithBasicConfig() throws Exception { String jsonString = Iterables.getOnlyElement( writer.writeConfig(Collections.singleton(apiConfig)).values()); assertNotNull(jsonString); JsonNode root = objectMapper.readValue(jsonString, JsonNode.class); assertEquals("myapi", root.path("name").asText()); assertEquals("v1", root.path("version").asText()); }
@Test public void apiCollation() throws Exception { ApiConfig config2 = configFactory.copy(apiConfig); ApiConfig config3 = configFactory.copy(apiConfig); ApiConfig config4 = configFactory.copy(apiConfig); ApiConfig config5 = configFactory.copy(apiConfig); ApiConfig config6 = configFactory.copy(apiConfig); config4.setVersion("v2"); config5.setVersion("v2"); config6.setName("differentApi"); Map<ApiKey, String> jsonConfigs = writer.writeConfig( ImmutableList.of(apiConfig, config2, config3, config4, config5, config6)); assertEquals(3, jsonConfigs.size()); assertThat(jsonConfigs.keySet()) .containsExactly(new ApiKey("myapi", "v1", "https: new ApiKey("myapi", "v2", "https: new ApiKey("differentApi", "v1", "https: }
@Test @Ignore("ignored until we find a proper solution") public void bodyFieldConflictsWithParameter() throws Exception { final class Endpoint { @SuppressWarnings("unused") public void set(@Named("date") String id, Bean resource) {} } new ApiConfigAnnotationReader().loadEndpointMethods(serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); try { writer.writeConfig(Collections.singleton(apiConfig)); fail(); } catch (PropertyParameterNameConflictException e) { } }
@Test public void idIsASpecialCaseForPropertyConflicts() throws Exception { final class Endpoint { @SuppressWarnings("unused") public void set(@Named("id") String id, IdBean resource) {} @SuppressWarnings("unused") public IdBean get(@Named("id") String id) { return null; } @SuppressWarnings("unused") public IdBean update(@Named("id") String id) { return null; } @SuppressWarnings("unused") public void remove(@Named("id") String id) {} } new ApiConfigAnnotationReader().loadEndpointMethods(serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); writer.writeConfig(Collections.singleton(apiConfig)); }
@Test public void responseFieldDoesNotConflictWithParameter() throws Exception { final class Endpoint { @SuppressWarnings("unused") public Bean get(@Named("date") String id) { return null; } } new ApiConfigAnnotationReader().loadEndpointMethods(serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); writer.writeConfig(Collections.singleton(apiConfig)); }
@Test public void enumResponseIsBlocked() throws Exception { final class Endpoint { @SuppressWarnings("unused") public TestEnum get() { return TestEnum.A; } } new ApiConfigAnnotationReader().loadEndpointMethods(serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); try { writer.writeConfig(Collections.singleton(apiConfig)); fail(); } catch (InvalidReturnTypeException e) { } }
@Test public void primitiveResponseIsBlocked() throws Exception { final class Endpoint { @SuppressWarnings("unused") public int get() { return 4; } } new ApiConfigAnnotationReader().loadEndpointMethods(serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); try { writer.writeConfig(Collections.singleton(apiConfig)); fail(); } catch (InvalidReturnTypeException e) { } }
@Test public void objectResponseIsAllowed() throws Exception { final class Endpoint { @SuppressWarnings("unused") public Bean get() { return null; } } new ApiConfigAnnotationReader().loadEndpointMethods(serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); writer.writeConfig(Collections.singleton(apiConfig)); }
@Test public void writeConfigOrderIsPreserved() throws Exception { @Api(name = "onetoday", description = "OneToday API") final class OneToday { } @Api(name = "onetodayadmin", description = "One Today Admin API") final class OneTodayAdmin { } ApiConfigValidator validator = Mockito.mock(ApiConfigValidator.class); TypeLoader typeLoader = new TypeLoader(); JsonConfigWriter writer = new JsonConfigWriter(new TypeLoader(JsonConfigWriter.class.getClassLoader()), validator); ApiConfig oneToday = new ApiConfig.Factory().create(serviceContext, typeLoader, OneToday.class); ApiConfig oneTodayAdmin = new ApiConfig.Factory().create(serviceContext, typeLoader, OneTodayAdmin.class); oneToday.setName("onetoday"); oneToday.setVersion("v1"); oneTodayAdmin.setName("onetodayadmin"); oneTodayAdmin.setVersion("v1"); Map<ApiKey, String> configs = writer.writeConfig(Lists.newArrayList(oneToday, oneTodayAdmin)); Iterator<ApiKey> iterator = configs.keySet().iterator(); assertEquals(new ApiKey("onetoday", "v1", "https: iterator.next()); assertEquals(new ApiKey("onetodayadmin", "v1", "https: iterator.next()); }
@Test public void writeConfigOrderIsPreservedMulticlass() throws Exception { @Api(name = "onetoday", description = "OneToday API") final class OneToday { } @Api(name = "onetoday", description = "OneToday API") final class OneToday2 { } @Api(name = "onetodayadmin", description = "One Today Admin API") final class OneTodayAdmin { } @Api(name = "onetodayadmin", description = "One Today Admin API") final class OneTodayAdmin2 { } ApiConfigValidator validator = Mockito.mock(ApiConfigValidator.class); TypeLoader typeLoader = new TypeLoader(); JsonConfigWriter writer = new JsonConfigWriter(new TypeLoader(JsonConfigWriter.class.getClassLoader()), validator); ApiConfig oneToday = new ApiConfig.Factory().create(serviceContext, typeLoader, OneToday.class); ApiConfig oneToday2 = new ApiConfig.Factory().create(serviceContext, typeLoader, OneToday2.class); ApiConfig oneTodayAdmin = new ApiConfig.Factory().create(serviceContext, typeLoader, OneTodayAdmin.class); ApiConfig oneTodayAdmin2 = new ApiConfig.Factory().create(serviceContext, typeLoader, OneTodayAdmin2.class); oneToday.setName("onetoday"); oneToday.setVersion("v1"); oneToday2.setName("onetoday"); oneToday2.setVersion("v1"); oneTodayAdmin.setName("onetodayadmin"); oneTodayAdmin.setVersion("v1"); oneTodayAdmin2.setName("onetodayadmin"); oneTodayAdmin2.setVersion("v1"); Map<ApiKey, String> configs = writer.writeConfig(Lists.newArrayList(oneToday, oneTodayAdmin, oneTodayAdmin2, oneToday2)); Iterator<ApiKey> iterator = configs.keySet().iterator(); assertEquals(new ApiKey("onetoday", "v1", "https: iterator.next()); assertEquals(new ApiKey("onetodayadmin", "v1", "https: iterator.next()); }
@Test public void writeConfigWithParameterizedTypeTransformerConfig() throws Exception { ApiConfig transformedApiConfig = configFactory.copy(apiConfig); transformedApiConfig.getSerializationConfig() .addSerializationConfig(ParameterizedTypeTransformer.class); final class Endpoint { @SuppressWarnings("unused") public ParameterizedBean get(@Named("date") String id) { return null; } } new ApiConfigAnnotationReader().loadEndpointMethods( serviceContext, Endpoint.class, transformedApiConfig.getApiClassConfig().getMethods()); writer.writeConfig(Collections.singleton(transformedApiConfig)); }
@Test public void writeConfigWithParameterizedTypeNoTransformerConfig() throws Exception { final class Endpoint { @SuppressWarnings("unused") public ParameterizedBean get(@Named("date") String id) { return null; } } new ApiConfigAnnotationReader().loadEndpointMethods( serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); Map<ApiKey, String> apiKeyStringMap = writer.writeConfig(Collections.singleton(apiConfig)); String configString = Iterables.getFirst(apiKeyStringMap.values(), null); assertThat(configString).contains("Qux_String"); }
@Test public void multipleResourceParametersErrorMessage() throws Exception { final class Endpoint { @SuppressWarnings("unused") public void get(Bean bean1, Bean bean2) { } } new ApiConfigAnnotationReader().loadEndpointMethods( serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); try { writer.writeConfig(Collections.singleton(apiConfig)); fail("Method with multiple resources should throw IllegalArgumentException"); } catch (IllegalArgumentException e) { assertThat(e.getMessage()).contains("cannot have multiple resource parameters"); } }
@Test public void ignoredMethod() throws Exception { final class Endpoint { @ApiMethod(ignored = AnnotationBoolean.TRUE) public void thisShouldBeIgnored() { } } new ApiConfigAnnotationReader().loadEndpointMethods( serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); for (String config : writer.writeConfig(Collections.singleton(apiConfig)).values()) { assertThat(config).doesNotContain("thisShouldBeIgnored"); } }
@Test public void standardParameters() throws Exception { final class Endpoint { public void standardParameters(@Named("alt") String alt, @Named("fields") String fields, @Named("key") String key, @Named("oauth_token") String oauthToken, @Named("prettyPrint") boolean prettyPrint, @Named("quotaUser") String quotaUser, @Named("userIp") String userIp) { } } new ApiConfigAnnotationReader().loadEndpointMethods( serviceContext, Endpoint.class, apiConfig.getApiClassConfig().getMethods()); for (String config : writer.writeConfig(Collections.singleton(apiConfig)).values()) { for (String param : StandardParameters.STANDARD_PARAM_NAMES) { assertThat(config).doesNotContain(param); } } }