This is an automated email from the ASF dual-hosted git repository.
bdelacretaz pushed a commit to branch feature/SLING-9550
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-graphql-core.git
The following commit(s) were added to refs/heads/feature/SLING-9550 by this
push:
new 1f61560 SLING-9550 - Use SlingScalarConverter services
1f61560 is described below
commit 1f615603fae31595aecb98027ec857dca0282500
Author: Bertrand Delacretaz <[email protected]>
AuthorDate: Fri Jun 26 15:55:22 2020 +0200
SLING-9550 - Use SlingScalarConverter services
---
...ge-info.java => ScalarConversionException.java} | 29 ++++--
.../sling/graphql/api/SlingScalarConverter.java | 46 +++++++++
.../org/apache/sling/graphql/api/package-info.java | 2 +-
.../graphql/core/engine/GraphQLResourceQuery.java | 2 +-
.../engine/SlingGraphQLException.java} | 20 ++--
.../graphql/core/scalars/SlingCoercingWrapper.java | 74 ++++++++++++++
.../graphql/core/scalars/SlingScalarsProvider.java | 109 ++++++++-------------
.../graphql/core/engine/CustomScalarsTest.java | 19 ++--
.../core/engine/GraphQLResourceQueryTest.java | 2 +-
.../graphql/core/engine/ResourceQueryTestBase.java | 8 +-
.../apache/sling/graphql/core/mocks/TestUtil.java | 7 ++
.../graphql/core/mocks/URLScalarConverter.java | 44 +++++++++
.../core/mocks/UppercaseScalarConverter.java} | 25 +++--
13 files changed, 288 insertions(+), 99 deletions(-)
diff --git a/src/main/java/org/apache/sling/graphql/api/package-info.java
b/src/main/java/org/apache/sling/graphql/api/ScalarConversionException.java
similarity index 59%
copy from src/main/java/org/apache/sling/graphql/api/package-info.java
copy to
src/main/java/org/apache/sling/graphql/api/ScalarConversionException.java
index c4934ad..bbb51e5 100644
--- a/src/main/java/org/apache/sling/graphql/api/package-info.java
+++ b/src/main/java/org/apache/sling/graphql/api/ScalarConversionException.java
@@ -17,10 +17,27 @@
* under the License.
*/
- /**
- * This package contains APIs which are independent of
- * a specific implementation of the underlying graphQL engine.
- */
-@Version("3.0.1")
package org.apache.sling.graphql.api;
-import org.osgi.annotation.versioning.Version;
\ No newline at end of file
+
+import javax.script.ScriptException;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Exception thrown by Scalar converters
+ */
+public class ScalarConversionException extends ScriptException {
+ private static final long serialVersionUID = 1L;
+
+ public ScalarConversionException(@NotNull String reason, @Nullable
Throwable cause) {
+ super(reason);
+ if(cause != null) {
+ initCause(cause);
+ }
+ }
+
+ public ScalarConversionException(@NotNull String reason) {
+ super(reason);
+ }
+}
diff --git
a/src/main/java/org/apache/sling/graphql/api/SlingScalarConverter.java
b/src/main/java/org/apache/sling/graphql/api/SlingScalarConverter.java
new file mode 100644
index 0000000..1d51b8b
--- /dev/null
+++ b/src/main/java/org/apache/sling/graphql/api/SlingScalarConverter.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.graphql.api;
+
+import org.jetbrains.annotations.Nullable;
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * A service that parses and serializes a custom GraphQL Scalar by
+ * converting between an eXternal type X an an inTernal one T.
+ *
+ * Instances of this service must have a {@link SlingScalarConverter.NAME}
+ * service property which is the name of the scalar type.
+ */
+@ConsumerType
+public interface SlingScalarConverter<T, X> {
+
+ String NAME_SERVICE_PROPERTY = "name";
+
+ /** Parse an external value (a query argument for example) into its
internal representation */
+ @Nullable
+ T parseValue(@Nullable X input) throws ScalarConversionException;
+
+ /** Serialize an internal value (provided by a {@link SlingDataFetcher}
into its
+ * external representation.
+ */
+ @Nullable
+ X serialize(@Nullable T value) throws ScalarConversionException;
+}
diff --git a/src/main/java/org/apache/sling/graphql/api/package-info.java
b/src/main/java/org/apache/sling/graphql/api/package-info.java
index c4934ad..496bec5 100644
--- a/src/main/java/org/apache/sling/graphql/api/package-info.java
+++ b/src/main/java/org/apache/sling/graphql/api/package-info.java
@@ -21,6 +21,6 @@
* This package contains APIs which are independent of
* a specific implementation of the underlying graphQL engine.
*/
-@Version("3.0.1")
+@Version("3.1.0")
package org.apache.sling.graphql.api;
import org.osgi.annotation.versioning.Version;
\ No newline at end of file
diff --git
a/src/main/java/org/apache/sling/graphql/core/engine/GraphQLResourceQuery.java
b/src/main/java/org/apache/sling/graphql/core/engine/GraphQLResourceQuery.java
index 9bdc733..711561d 100644
---
a/src/main/java/org/apache/sling/graphql/core/engine/GraphQLResourceQuery.java
+++
b/src/main/java/org/apache/sling/graphql/core/engine/GraphQLResourceQuery.java
@@ -116,7 +116,7 @@ public class GraphQLResourceQuery {
private GraphQLSchema buildSchema(String sdl, SlingDataFetcherSelector
fetchers, SlingScalarsProvider scalarsProvider, Resource currentResource)
throws IOException {
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
- Iterable<GraphQLScalarType> scalars =
scalarsProvider.getScalars(typeRegistry.scalars());
+ Iterable<GraphQLScalarType> scalars =
scalarsProvider.getCustomScalars(typeRegistry.scalars());
RuntimeWiring runtimeWiring = buildWiring(typeRegistry, fetchers,
scalars, currentResource);
SchemaGenerator schemaGenerator = new SchemaGenerator();
return schemaGenerator.makeExecutableSchema(typeRegistry,
runtimeWiring);
diff --git a/src/main/java/org/apache/sling/graphql/api/package-info.java
b/src/main/java/org/apache/sling/graphql/core/engine/SlingGraphQLException.java
similarity index 69%
copy from src/main/java/org/apache/sling/graphql/api/package-info.java
copy to
src/main/java/org/apache/sling/graphql/core/engine/SlingGraphQLException.java
index c4934ad..9e213f1 100644
--- a/src/main/java/org/apache/sling/graphql/api/package-info.java
+++
b/src/main/java/org/apache/sling/graphql/core/engine/SlingGraphQLException.java
@@ -17,10 +17,16 @@
* under the License.
*/
- /**
- * This package contains APIs which are independent of
- * a specific implementation of the underlying graphQL engine.
- */
-@Version("3.0.1")
-package org.apache.sling.graphql.api;
-import org.osgi.annotation.versioning.Version;
\ No newline at end of file
+package org.apache.sling.graphql.core.engine;
+
+public class SlingGraphQLException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public SlingGraphQLException(String reason, Throwable cause) {
+ super(reason, cause);
+ }
+
+ public SlingGraphQLException(String reason) {
+ super(reason);
+ }
+}
\ No newline at end of file
diff --git
a/src/main/java/org/apache/sling/graphql/core/scalars/SlingCoercingWrapper.java
b/src/main/java/org/apache/sling/graphql/core/scalars/SlingCoercingWrapper.java
new file mode 100644
index 0000000..4ff19dd
--- /dev/null
+++
b/src/main/java/org/apache/sling/graphql/core/scalars/SlingCoercingWrapper.java
@@ -0,0 +1,74 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.graphql.core.scalars;
+
+import org.apache.sling.graphql.api.ScalarConversionException;
+import org.apache.sling.graphql.api.SlingScalarConverter;
+
+import graphql.language.StringValue;
+import graphql.schema.Coercing;
+import graphql.schema.CoercingParseLiteralException;
+import graphql.schema.CoercingParseValueException;
+import graphql.schema.CoercingSerializeException;
+
+/** Wraps {@link SlingScalarConverter} into a GraphQL-java Coercing */
+class SlingCoercingWrapper implements Coercing<Object, Object> {
+ private final SlingScalarConverter<Object, Object> converter;
+
+ SlingCoercingWrapper(SlingScalarConverter<Object, Object> c) {
+ converter = c;
+ }
+
+ @Override
+ public Object serialize(Object dataFetcherResult) throws
CoercingSerializeException {
+ try {
+ return converter.serialize(dataFetcherResult);
+ } catch(ScalarConversionException sce) {
+ throw new CoercingSerializeException(sce);
+ }
+ }
+
+ @Override
+ public Object parseValue(Object input) throws CoercingParseValueException {
+ try {
+ return converter.parseValue(input);
+ } catch(ScalarConversionException sce) {
+ throw new CoercingSerializeException(sce);
+ }
+ }
+
+ @Override
+ public Object parseLiteral(Object input) throws
CoercingParseLiteralException {
+ // This is called when parsing objects from the GraphQL Abstract
Syntax Tree
+ // So far we handle StringValue only and unfortunately there's no
common
+ // interface for the getValue() method.
+ try {
+ if(input instanceof StringValue) {
+ return converter.parseValue(((StringValue)input).getValue());
+ } else {
+ return converter.parseValue(input);
+ }
+ } catch(ScalarConversionException sce) {
+ throw new CoercingSerializeException(sce);
+ }
+ }
+
+ }
\ No newline at end of file
diff --git
a/src/main/java/org/apache/sling/graphql/core/scalars/SlingScalarsProvider.java
b/src/main/java/org/apache/sling/graphql/core/scalars/SlingScalarsProvider.java
index 4fa3ac7..8ffde2e 100644
---
a/src/main/java/org/apache/sling/graphql/core/scalars/SlingScalarsProvider.java
+++
b/src/main/java/org/apache/sling/graphql/core/scalars/SlingScalarsProvider.java
@@ -20,20 +20,23 @@
package org.apache.sling.graphql.core.scalars;
-import java.net.URL;
import java.util.Map;
import java.util.stream.Collectors;
+import javax.script.ScriptException;
+
+import org.apache.sling.graphql.api.SlingScalarConverter;
+import org.apache.sling.graphql.core.engine.SlingGraphQLException;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import graphql.language.ScalarTypeDefinition;
-import graphql.language.StringValue;
-import graphql.schema.Coercing;
-import graphql.schema.CoercingParseLiteralException;
-import graphql.schema.CoercingParseValueException;
-import graphql.schema.CoercingSerializeException;
import graphql.schema.GraphQLScalarType;
+import graphql.schema.idl.ScalarInfo;
/**
* Provides GraphQL Scalars (leaf data types) for query execution
@@ -43,78 +46,50 @@ import graphql.schema.GraphQLScalarType;
Constants.SERVICE_VENDOR + "=The Apache Software Foundation" })
public class SlingScalarsProvider {
- static class URLCoercing implements Coercing<URL, String> {
- static final String NAME = "URL";
-
- @Override
- public String serialize(Object dataFetcherResult) throws
CoercingSerializeException {
- if(dataFetcherResult instanceof URL) {
- return getClass().getSimpleName() + " says:" +
((URL)dataFetcherResult).toExternalForm();
- }
- throw new CoercingSerializeException("Unexpected serialize input "
+ dataFetcherResult);
- }
-
- @Override
- public URL parseValue(Object input) throws CoercingParseValueException
{
- try {
- return new URL(String.valueOf(input));
- } catch(Exception e) {
- throw new CoercingParseValueException("URL parsing failed ",
e);
- }
- }
-
- @Override
- public URL parseLiteral(Object input) throws
CoercingParseLiteralException {
- if(input instanceof StringValue) {
- return parseValue(((StringValue)input).getValue());
-
- }
- throw new CoercingSerializeException("Unexpected parse input " +
input);
- }
-
+ private BundleContext bundleContext;
+
+ @Activate
+ public void activate(BundleContext ctx) {
+ bundleContext = ctx;
}
- static class UppercaseStringCoercing implements Coercing<String, String> {
- static final String NAME = "UppercaseString";
+ @SuppressWarnings("unchecked")
+ private GraphQLScalarType getScalar(String name) {
- @Override
- public String serialize(Object dataFetcherResult) throws
CoercingSerializeException {
- return String.valueOf(dataFetcherResult).toUpperCase();
+ // Ignore standard scalars
+ if(ScalarInfo.STANDARD_SCALAR_DEFINITIONS.containsKey(name)) {
+ return null;
}
- @Override
- public String parseValue(Object input) throws
CoercingParseValueException {
- throw new CoercingParseValueException("Parsing not implemented");
+ SlingScalarConverter<Object, Object> converter = null;
+ final String filter = String.format("(%s=%s)",
SlingScalarConverter.NAME_SERVICE_PROPERTY, name);
+ ServiceReference<?>[] refs= null;
+ try {
+ refs =
bundleContext.getServiceReferences(SlingScalarConverter.class.getName(),
filter);
+ } catch(InvalidSyntaxException ise) {
+ throw new SlingGraphQLException("Invalid OSGi filter syntax:" +
filter);
}
-
- @Override
- public String parseLiteral(Object input) throws
CoercingParseLiteralException {
- throw new CoercingParseValueException("Parsing not implemented");
+ if(refs != null) {
+ // SlingScalarConverter services must have a unique name for now
+ // (we might use a namespacing @directive in the schema to allow
multiple ones with the same name)
+ if(refs.length > 1) {
+ throw new SlingGraphQLException(String.format("Got %d services
for %s, expected just one", refs.length, filter));
+ }
+ converter = (SlingScalarConverter<Object,
Object>)bundleContext.getService(refs[0]);
}
- }
-
- private GraphQLScalarType getScalar(String name) {
- if(URLCoercing.NAME.equals(name)) {
- return GraphQLScalarType.newScalar()
- .name(URLCoercing.NAME)
- .description("TODO should be an OSGi service - hardcoded for
initial tests")
- .coercing(new URLCoercing())
- .build()
- ;
+ if(converter == null) {
+ throw new SlingGraphQLException("SlingScalarConverter with name '"
+ name + "' not found");
}
- if(UppercaseStringCoercing.NAME.equals(name)) {
- return GraphQLScalarType.newScalar()
- .name(UppercaseStringCoercing.NAME)
- .description("TODO should be an OSGi service - hardcoded for
initial tests")
- .coercing(new UppercaseStringCoercing())
- .build()
- ;
- }
- return null;
+
+ return GraphQLScalarType.newScalar()
+ .name(name)
+ .description(converter.toString())
+ .coercing(new SlingCoercingWrapper(converter))
+ .build();
}
- public Iterable<GraphQLScalarType>
getScalars(Map<String,ScalarTypeDefinition> schemaScalars) {
+ public Iterable<GraphQLScalarType>
getCustomScalars(Map<String,ScalarTypeDefinition> schemaScalars) {
// Using just the names for now, not sure why we'd need the
ScalarTypeDefinitions
return schemaScalars.keySet().stream()
.map(this::getScalar)
diff --git
a/src/test/java/org/apache/sling/graphql/core/engine/CustomScalarsTest.java
b/src/test/java/org/apache/sling/graphql/core/engine/CustomScalarsTest.java
index f3a17fc..c633da4 100644
--- a/src/test/java/org/apache/sling/graphql/core/engine/CustomScalarsTest.java
+++ b/src/test/java/org/apache/sling/graphql/core/engine/CustomScalarsTest.java
@@ -22,12 +22,13 @@ import static
com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.junit.Assert.assertThat;
-import javax.script.ScriptException;
-
import static org.hamcrest.Matchers.equalTo;
+import org.apache.sling.graphql.api.ScalarConversionException;
import org.apache.sling.graphql.core.mocks.AddressDataFetcher;
import org.apache.sling.graphql.core.mocks.TestUtil;
+import org.apache.sling.graphql.core.mocks.URLScalarConverter;
+import org.apache.sling.graphql.core.mocks.UppercaseScalarConverter;
import org.junit.Test;
public class CustomScalarsTest extends ResourceQueryTestBase {
@@ -35,8 +36,10 @@ public class CustomScalarsTest extends ResourceQueryTestBase
{
return "scalars-schema";
}
- protected void setupDataFetchers() {
+ protected void setupAdditionalServices() {
TestUtil.registerSlingDataFetcher(context.bundleContext(),
"scalars/address", new AddressDataFetcher());
+ TestUtil.registerSlingScalarConverter(context.bundleContext(), "URL",
new URLScalarConverter());
+ TestUtil.registerSlingScalarConverter(context.bundleContext(),
"UppercaseString", new UppercaseScalarConverter());
}
@Test
@@ -45,14 +48,18 @@ public class CustomScalarsTest extends
ResourceQueryTestBase {
final String query = String.format("{ address (url: \"%s\") { url
hostname } }", url);
final String json = queryJSON(query);
assertThat(json, hasJsonPath("$.data.address.hostname",
equalTo("WWW.PERDU.COM")));
- assertThat(json, hasJsonPath("$.data.address.url",
equalTo("URLCoercing says:" + url)));
+ assertThat(json, hasJsonPath("$.data.address.url",
equalTo("URLScalarConverter says:" + url)));
}
- @Test(expected = ScriptException.class)
+ @Test
public void urlSyntaxError() throws Exception {
final String url = "This is not an URL!";
final String query = String.format("{ address (url: \"%s\") { url
hostname } }", url);
- queryJSON(query);
+ try {
+ queryJSON(query);
+ } catch(Exception e) {
+ TestUtil.assertNestedException(e, ScalarConversionException.class,
URLScalarConverter.class.getSimpleName() + ":Invalid URL:" + url);
+ }
}
}
\ No newline at end of file
diff --git
a/src/test/java/org/apache/sling/graphql/core/engine/GraphQLResourceQueryTest.java
b/src/test/java/org/apache/sling/graphql/core/engine/GraphQLResourceQueryTest.java
index 6cc707c..a11ad64 100644
---
a/src/test/java/org/apache/sling/graphql/core/engine/GraphQLResourceQueryTest.java
+++
b/src/test/java/org/apache/sling/graphql/core/engine/GraphQLResourceQueryTest.java
@@ -40,7 +40,7 @@ import org.osgi.framework.ServiceRegistration;
public class GraphQLResourceQueryTest extends ResourceQueryTestBase {
- protected void setupDataFetchers() {
+ protected void setupAdditionalServices() {
final Dictionary<String, Object> staticData = new Hashtable<>();
staticData.put("test", true);
diff --git
a/src/test/java/org/apache/sling/graphql/core/engine/ResourceQueryTestBase.java
b/src/test/java/org/apache/sling/graphql/core/engine/ResourceQueryTestBase.java
index 6df9d72..5c6504d 100644
---
a/src/test/java/org/apache/sling/graphql/core/engine/ResourceQueryTestBase.java
+++
b/src/test/java/org/apache/sling/graphql/core/engine/ResourceQueryTestBase.java
@@ -44,7 +44,7 @@ import graphql.ExecutionResult;
public abstract class ResourceQueryTestBase {
protected SchemaProvider schemaProvider;
protected SlingDataFetcherSelector dataFetchersSelector;
- protected SlingScalarsProvider scalarsProvider = new
SlingScalarsProvider();
+ protected SlingScalarsProvider scalarsProvider;
protected Resource resource;
@Rule
@@ -59,7 +59,7 @@ public abstract class ResourceQueryTestBase {
Mockito.when(resource.getPath()).thenReturn(path);
Mockito.when(resource.getResourceType()).thenReturn(resourceType);
- setupDataFetchers();
+ setupAdditionalServices();
// Our MockScriptServlet to simulates a script for unit tests, for the
// integration tests we use a real script
@@ -71,6 +71,8 @@ public abstract class ResourceQueryTestBase {
context.registerInjectActivateService(new
ScriptedDataFetcherProvider());
context.registerInjectActivateService(new SlingDataFetcherSelector());
dataFetchersSelector =
context.getService(SlingDataFetcherSelector.class);
+ context.registerInjectActivateService(new SlingScalarsProvider());
+ scalarsProvider = context.getService(SlingScalarsProvider.class);
}
protected String queryJSON(String stmt) throws Exception {
@@ -84,7 +86,7 @@ public abstract class ResourceQueryTestBase {
return new JsonSerializer().toJSON(result);
}
- protected void setupDataFetchers() {
+ protected void setupAdditionalServices() {
}
protected String getTestSchemaName() {
diff --git a/src/test/java/org/apache/sling/graphql/core/mocks/TestUtil.java
b/src/test/java/org/apache/sling/graphql/core/mocks/TestUtil.java
index 7679108..2f85566 100644
--- a/src/test/java/org/apache/sling/graphql/core/mocks/TestUtil.java
+++ b/src/test/java/org/apache/sling/graphql/core/mocks/TestUtil.java
@@ -25,6 +25,7 @@ import java.util.Dictionary;
import java.util.Hashtable;
import org.apache.sling.graphql.api.SlingDataFetcher;
+import org.apache.sling.graphql.api.SlingScalarConverter;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
@@ -35,6 +36,12 @@ public class TestUtil {
return bc.registerService(SlingDataFetcher.class, f, props);
}
+ public static ServiceRegistration<?>
registerSlingScalarConverter(BundleContext bc, String name,
SlingScalarConverter<?,?> c) {
+ final Dictionary<String, Object> props = new Hashtable<>();
+ props.put(SlingScalarConverter.NAME_SERVICE_PROPERTY, name);
+ return bc.registerService(SlingScalarConverter.class, c, props);
+ }
+
public static void assertNestedException(Throwable t, Class<?> clazz,
String messageContains) {
boolean found = false;
while(t != null) {
diff --git
a/src/test/java/org/apache/sling/graphql/core/mocks/URLScalarConverter.java
b/src/test/java/org/apache/sling/graphql/core/mocks/URLScalarConverter.java
new file mode 100644
index 0000000..7a12c52
--- /dev/null
+++ b/src/test/java/org/apache/sling/graphql/core/mocks/URLScalarConverter.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.graphql.core.mocks;
+
+import java.net.URL;
+
+import org.apache.sling.graphql.api.ScalarConversionException;
+import org.apache.sling.graphql.api.SlingScalarConverter;
+import org.jetbrains.annotations.Nullable;
+
+public class URLScalarConverter implements SlingScalarConverter<URL, String> {
+
+ @Override
+ public @Nullable URL parseValue(@Nullable String input) throws
ScalarConversionException {
+ try {
+ return new URL(input);
+ } catch(Exception e) {
+ throw new ScalarConversionException(getClass().getSimpleName() +
":Invalid URL:" + input, e);
+ }
+ }
+
+ @Override
+ public @Nullable String serialize(@Nullable URL value) throws
ScalarConversionException {
+ final String testPrefix = getClass().getSimpleName() + " says:";
+ return testPrefix + (value == null ? null : value.toExternalForm());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/graphql/api/package-info.java
b/src/test/java/org/apache/sling/graphql/core/mocks/UppercaseScalarConverter.java
similarity index 54%
copy from src/main/java/org/apache/sling/graphql/api/package-info.java
copy to
src/test/java/org/apache/sling/graphql/core/mocks/UppercaseScalarConverter.java
index c4934ad..dd0c2fd 100644
--- a/src/main/java/org/apache/sling/graphql/api/package-info.java
+++
b/src/test/java/org/apache/sling/graphql/core/mocks/UppercaseScalarConverter.java
@@ -17,10 +17,21 @@
* under the License.
*/
- /**
- * This package contains APIs which are independent of
- * a specific implementation of the underlying graphQL engine.
- */
-@Version("3.0.1")
-package org.apache.sling.graphql.api;
-import org.osgi.annotation.versioning.Version;
\ No newline at end of file
+package org.apache.sling.graphql.core.mocks;
+
+import org.apache.sling.graphql.api.ScalarConversionException;
+import org.apache.sling.graphql.api.SlingScalarConverter;
+import org.jetbrains.annotations.Nullable;
+
+public class UppercaseScalarConverter implements SlingScalarConverter<String,
String> {
+
+ @Override
+ public @Nullable String parseValue(@Nullable String input) throws
ScalarConversionException {
+ throw new ScalarConversionException("This converter is meant for
output only");
+ }
+
+ @Override
+ public @Nullable String serialize(@Nullable String value) throws
ScalarConversionException {
+ return value == null ? null : value.toUpperCase();
+ }
+}
\ No newline at end of file