com.google.api.server.spi.config.annotationreader.ApiAnnotationIntrospectorTest.java Source code

Java tutorial

Introduction

Here is the source code for com.google.api.server.spi.config.annotationreader.ApiAnnotationIntrospectorTest.java

Source

/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed 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 com.google.api.server.spi.config.annotationreader;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import com.google.api.server.spi.ObjectMapperUtil;
import com.google.api.server.spi.ServiceContext;
import com.google.api.server.spi.TypeLoader;
import com.google.api.server.spi.config.AnnotationBoolean;
import com.google.api.server.spi.config.ApiResourceProperty;
import com.google.api.server.spi.config.ApiTransformer;
import com.google.api.server.spi.config.ResourcePropertySchema;
import com.google.api.server.spi.config.ResourceSchema;
import com.google.api.server.spi.config.ResourceTransformer;
import com.google.api.server.spi.config.Transformer;
import com.google.api.server.spi.config.model.ApiConfig;
import com.google.api.server.spi.config.model.ApiSerializationConfig;
import com.google.api.server.spi.testing.DefaultValueSerializer;
import com.google.api.server.spi.testing.TestEndpoint;
import com.google.common.base.MoreObjects;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.TypeToken;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.Map;

/**
 * Tests for {@link ApiAnnotationIntrospector}. These tests actually test serialization using the
 * introspector, rather than the introspector methods themselves, which aren't that interesting.
 */
@RunWith(JUnit4.class)
public class ApiAnnotationIntrospectorTest {
    private ObjectMapper objectMapper = null;

    @Before
    public void setUp() throws Exception {
        objectMapper = ObjectMapperUtil.createStandardObjectMapper();
    }

    @Test
    public void testSerializeApiNameOnGetter() throws Exception {
        testSerializeApiName(TestApiNameOnGetter.class);
    }

    @Test
    public void testDeserializeApiNameOnGetter() throws Exception {
        testDeserializeApiName(TestApiNameOnGetter.class);
    }

    @Test
    public void testSerializeApiNameOnSetter() throws Exception {
        testSerializeApiName(TestApiNameOnSetter.class);
    }

    @Test
    public void testDeserializeApiNameOnSetter() throws Exception {
        testDeserializeApiName(TestApiNameOnSetter.class);
    }

    @Test
    public void testSerializeApiIgnoreOnGetter() throws Exception {
        testSerializeApiIgnore(TestApiIgnoreOnGetter.class);
    }

    @Test
    public void testDeserializeApiIgnoreOnGetter() throws Exception {
        testDeserializeApiIgnore(TestApiIgnoreOnGetter.class);
    }

    @Test
    public void testSerializeApiIgnoreOnSetter() throws Exception {
        testSerializeApiIgnore(TestApiIgnoreOnSetter.class);
    }

    @Test
    public void testDeserializeApiIgnoreOnSetter() throws Exception {
        testDeserializeApiIgnore(TestApiIgnoreOnSetter.class);
    }

    @Test
    public void testSerializeCustomResourceSerializer() throws Exception {
        TestResourceWithCustomSerializer obj = new TestResourceWithCustomSerializer();
        obj.point = "7,8";
        obj.nested = new TestSerializePublicField();
        obj.nested.foo = "bar";
        String json = objectMapper.writeValueAsString(obj);
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertEquals(7, value.path("x").asInt());
        assertEquals(8, value.path("y").asInt());
        assertEquals("bar", value.path("nestedResource").path("foo").asText());
    }

    @Test
    public void testDeserializeCustomResourceSerializer() throws Exception {
        String json = "{\"nestedResource\": {\"foo\": \"baz\"}, \"y\": 42, \"notAField\": 123, "
                + "\"alsoNotAField\": {\"y\": 43}}";
        TestResourceWithCustomSerializer value = objectMapper.readValue(json,
                TestResourceWithCustomSerializer.class);
        assertEquals("0,42", value.point);
        assertNotNull(value.nested);
        assertEquals("baz", value.nested.foo);
    }

    @Test
    public void testSerializeCustomResourceSerializerInheritance() throws Exception {
        TestChildResourceWithCustomSerializer obj = new TestChildResourceWithCustomSerializer();
        obj.point = "1,2";
        obj.nested = new TestSerializePublicField();
        obj.nested.foo = null;
        obj.number = 123;
        String json = objectMapper.writeValueAsString(obj);
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertEquals(1, value.path("x").asInt());
        assertEquals(2, value.path("y").asInt());
        assertTrue(value.path("nestedResource").path("foo").isNull());
        assertEquals(123, value.path("aShort").asInt());
    }

    @Test
    public void testDeserializeCustomResourceSerializerInheritance() throws Exception {
        String json = "{\"nestedResource\": {}, \"aShort\": 99}";
        TestChildResourceWithCustomSerializer value = objectMapper.readValue(json,
                TestChildResourceWithCustomSerializer.class);
        assertEquals("0,0", value.point);
        assertNotNull(value.nested);
        assertEquals("test", value.nested.foo);
        assertEquals(new Short((short) 99), value.number);
    }

    @Test
    public void testSerializePublicField() throws Exception {
        String json = objectMapper.writeValueAsString(new TestSerializePublicField());
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertEquals("test", value.path("foo").asText());
    }

    @Test
    public void testDeserializePublicField() throws Exception {
        String json = "{\"foo\": \"bar\"}";
        TestSerializePublicField value = objectMapper.readValue(json, TestSerializePublicField.class);
        assertEquals("bar", value.foo);
    }

    @Test
    public void testSerializePrivateField() throws Exception {
        String json = objectMapper.writeValueAsString(new TestSerializePrivateField());
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertTrue(value.path("foo").isMissingNode());
    }

    @Test
    public void testDeserializePrivateField() throws Exception {
        String json = "{\"foo\": \"bar\"}";
        TestSerializePrivateField value = objectMapper.readValue(json, TestSerializePrivateField.class);
        assertEquals("test", value.foo);
    }

    @Test
    public void testSerializeAnnotatedPrivateField() throws Exception {
        String json = objectMapper.writeValueAsString(new TestSerializeAnnotatedPrivateField());
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertEquals("test", value.path("foo").asText());
    }

    @Test
    public void testDeserializeAnnotatedPrivateField() throws Exception {
        String json = "{\"foo\": \"bar\"}";
        TestSerializeAnnotatedPrivateField value = objectMapper.readValue(json,
                TestSerializeAnnotatedPrivateField.class);
        assertEquals("bar", value.foo);
    }

    @Test
    public void testSerializePublicIgnoredField() throws Exception {
        String json = objectMapper.writeValueAsString(new TestSerializePrivateField());
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertTrue(value.path("foo").isMissingNode());
    }

    @Test
    public void testDeserializePublicIgnoredField() throws Exception {
        String json = "{\"foo\": \"bar\"}";
        TestSerializePrivateField value = objectMapper.readValue(json, TestSerializePrivateField.class);
        assertEquals("test", value.foo);
    }

    @Test
    public void testApiSerializationByConfig() throws Exception {
        ApiSerializationConfig config = new ApiSerializationConfig();
        config.addSerializationConfig(TestApiSerializationByConfigConverter.class);
        objectMapper.setAnnotationIntrospector(new ApiAnnotationIntrospector(config));
        String json = objectMapper.writeValueAsString(new TestApiSerializationByConfig());
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertEquals("testserialized", value.asText());
    }

    @Test
    public void testApiDeserializationByConfig() throws Exception {
        ApiSerializationConfig config = new ApiSerializationConfig();
        config.addSerializationConfig(TestApiSerializationByConfigConverter.class);
        objectMapper.setAnnotationIntrospector(new ApiAnnotationIntrospector(config));
        TestApiSerializationByConfig value = objectMapper.readValue("\"test2serialized\"",
                TestApiSerializationByConfig.class);
        assertEquals("test2", value.getFoo());
    }

    @Test
    public void testApiSerializationByParameterizedConfig() throws Exception {
        ApiSerializationConfig config = new ApiSerializationConfig();
        config.addSerializationConfig(TestApiSerializationByParameterizedConfigConverter.class);
        objectMapper.setAnnotationIntrospector(new ApiAnnotationIntrospector(config));
        String json = objectMapper
                .writeValueAsString(new TestApiSerializationByParameterizedConfig<String>("paramtest"));
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertEquals("paramtestserialized", value.asText());
    }

    @Test
    public void testApiDeserializationByParameterizedConfig() throws Exception {
        ApiSerializationConfig config = new ApiSerializationConfig();
        config.addSerializationConfig(TestApiSerializationByParameterizedConfigConverter.class);
        objectMapper.setAnnotationIntrospector(new ApiAnnotationIntrospector(config));
        TestApiSerializationByParameterizedConfig value = objectMapper.readValue("\"paramtest2serialized\"",
                TestApiSerializationByParameterizedConfig.class);
        assertEquals("paramtest2", value.getBar());
    }

    @Test
    public void testApiSerializationByAnnotation() throws Exception {
        String json = objectMapper.writeValueAsString(new TestApiSerializationByAnnotation());
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertEquals("testserialized", value.asText());
    }

    @Test
    public void testApiDeserializationByAnnotation() throws Exception {
        TestApiSerializationByAnnotation value = objectMapper.readValue("\"test2serialized\"",
                TestApiSerializationByAnnotation.class);
        assertEquals("test2", value.getFoo());
    }

    @Test
    public void testApiSerializationToComplex() throws Exception {
        String json = objectMapper.writeValueAsString(new TestApiSerializationToComplex());
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertEquals("test", value.path("bar").asText());
    }

    @Test
    public void testApiDeserializationToComplex() throws Exception {
        TestApiSerializationToComplex value = objectMapper.readValue("{\"bar\": \"test2\"}",
                TestApiSerializationToComplex.class);
        assertEquals("test2", value.getFoo());
    }

    @Test
    public void testGetSerializerTypeWithIncompatibleSourceType() throws Exception {
        try {
            ApiConfig config = new ApiConfig.Factory().create(ServiceContext.create(), new TypeLoader(),
                    TestEndpoint.class);
            ApiAnnotationIntrospector.getSchemaType(TypeToken.of(BadSerializerBean.class), config);
            fail("no exception thrown when a bad serializer was specified");
        } catch (IllegalArgumentException e) {
            // expected
        }
    }

    private void testSerializeApiName(Class<? extends Foo> testApiNameClass) throws Exception {
        String json = objectMapper.writeValueAsString(testApiNameClass.newInstance());
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertEquals("test", value.path("bar").asText());
    }

    private void testDeserializeApiName(Class<? extends Foo> testApiNameClass) throws Exception {
        String json = "{\"bar\": \"foo\"}";
        Foo value = objectMapper.readValue(json, testApiNameClass);
        assertEquals("foo", value.getFoo());
    }

    private void testSerializeApiIgnore(Class<? extends Foo> testApiIgnoreClass) throws Exception {
        String json = objectMapper.writeValueAsString(testApiIgnoreClass.newInstance());
        JsonNode value = objectMapper.readValue(json, JsonNode.class);
        assertTrue(value.path("foo").isMissingNode());
    }

    private void testDeserializeApiIgnore(Class<? extends Foo> testApiIgnoreClass) throws Exception {
        String json = "{\"foo\": \"foo\"}";
        Foo value = objectMapper.readValue(json, testApiIgnoreClass);
        assertEquals("test", value.getFoo());
    }

    public interface Foo {
        String getFoo();

        void setFoo(String foo);
    }

    /**
     * Parameterized interface used to test transformer operation on ParameterizedType.
     */
    public interface Bar<T> {
        T getBar();

        void setBar(T bar);
    }

    public static class TestApiNameOnGetter implements Foo {
        private String foo = "test";

        @Override
        @ApiResourceProperty(name = "bar")
        public String getFoo() {
            return foo;
        }

        @Override
        public void setFoo(String foo) {
            this.foo = foo;
        }
    }

    public static class TestApiNameOnSetter implements Foo {
        private String foo = "test";

        @Override
        public String getFoo() {
            return foo;
        }

        @Override
        @ApiResourceProperty(name = "bar")
        public void setFoo(String foo) {
            this.foo = foo;
        }
    }

    public static class TestApiIgnoreOnGetter implements Foo {
        private String foo = "test";

        @Override
        @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
        public String getFoo() {
            return foo;
        }

        @Override
        public void setFoo(String foo) {
            this.foo = foo;
        }

        public String getBar() {
            return null;
        }
    }

    public static class TestApiIgnoreOnSetter implements Foo {
        private String foo = "test";

        @Override
        public String getFoo() {
            return foo;
        }

        @Override
        @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
        public void setFoo(String foo) {
            this.foo = foo;
        }

        public String getBar() {
            return null;
        }
    }

    public static class TestApiSerializationByConfig implements Foo {
        private String foo = "test";

        @Override
        public String getFoo() {
            return foo;
        }

        @Override
        public void setFoo(String foo) {
            this.foo = foo;
        }
    }

    public static class TestApiSerializationByConfigConverter
            implements Transformer<TestApiSerializationByConfig, String> {

        @Override
        public String transformTo(TestApiSerializationByConfig in) {
            return in.getFoo() + "serialized";
        }

        @Override
        public TestApiSerializationByConfig transformFrom(String in) {
            TestApiSerializationByConfig obj = new TestApiSerializationByConfig();
            obj.setFoo(in.replace("serialized", ""));
            return obj;
        }
    }

    /**
     * An implementation of {@code Bar} for parameterized testing.
     */
    public static class TestApiSerializationByParameterizedConfig<T> implements Bar<T> {
        private T bar;

        TestApiSerializationByParameterizedConfig(T bar) {
            setBar(bar);
        }

        @Override
        public T getBar() {
            return bar;
        }

        @Override
        public void setBar(T bar) {
            this.bar = bar;
        }
    }

    /**
     * A (non-parameterized) Transformer operating on a parameterized type.
     */
    public static class TestApiSerializationByParameterizedConfigConverter
            implements Transformer<TestApiSerializationByParameterizedConfig, String> {

        @Override
        public String transformTo(TestApiSerializationByParameterizedConfig in) {
            return in.getBar().toString() + "serialized";
        }

        @Override
        public TestApiSerializationByParameterizedConfig transformFrom(String in) {
            return new TestApiSerializationByParameterizedConfig<String>(in.replace("serialized", ""));
        }
    }

    @ApiTransformer(TestApiSerializationByAnnotationConverter.class)
    public static class TestApiSerializationByAnnotation implements Foo {
        private String foo = "test";

        @Override
        public String getFoo() {
            return foo;
        }

        @Override
        public void setFoo(String foo) {
            this.foo = foo;
        }
    }

    public static class TestApiSerializationByAnnotationConverter
            implements Transformer<TestApiSerializationByAnnotation, String> {

        @Override
        public String transformTo(TestApiSerializationByAnnotation in) {
            return in.getFoo() + "serialized";
        }

        @Override
        public TestApiSerializationByAnnotation transformFrom(String in) {
            TestApiSerializationByAnnotation obj = new TestApiSerializationByAnnotation();
            obj.setFoo(in.replace("serialized", ""));
            return obj;
        }
    }

    public static class Complex {
        private String bar;

        public Complex() {
        }

        public Complex(String bar) {
            this.bar = bar;
        }

        public String getBar() {
            return bar;
        }

        public void setBar(String bar) {
            this.bar = bar;
        }
    }

    @ApiTransformer(TestApiSerializationToComplexConverter.class)
    public static class TestApiSerializationToComplex implements Foo {
        private String foo = "test";

        @Override
        public String getFoo() {
            return foo;
        }

        @Override
        public void setFoo(String foo) {
            this.foo = foo;
        }
    }

    public static class TestApiSerializationToComplexConverter
            implements Transformer<TestApiSerializationToComplex, Complex> {

        @Override
        public Complex transformTo(TestApiSerializationToComplex in) {
            return new Complex(in.getFoo());
        }

        @Override
        public TestApiSerializationToComplex transformFrom(Complex in) {
            TestApiSerializationToComplex obj = new TestApiSerializationToComplex();
            obj.setFoo(in.getBar());
            return obj;
        }
    }

    public static class SuperSerializer extends DefaultValueSerializer<String, Integer> {
    }

    @ApiTransformer(BadSerializer.class)
    public static class BadSerializerBean {
    }

    public static class BadSerializer extends DefaultValueSerializer<String, Integer> {
    }

    @ApiTransformer(CustomResourceSerializer.class)
    public static class TestResourceWithCustomSerializer {
        public String point = "0,0";
        public TestSerializePublicField nested;
    }

    public static class TestChildResourceWithCustomSerializer extends TestResourceWithCustomSerializer {
        public Short number = 25;
    }

    // A resource serializer with inheritance.
    public static class CustomResourceSerializer implements ResourceTransformer<TestResourceWithCustomSerializer> {

        private Class<? extends TestResourceWithCustomSerializer> clazz;

        public CustomResourceSerializer(Class<? extends TestResourceWithCustomSerializer> clazz) {
            this.clazz = clazz;
        }

        @Override
        public Map<String, Object> transformTo(TestResourceWithCustomSerializer in) {
            ImmutableMap.Builder<String, Object> resultBuilder = ImmutableMap.builder();
            resultBuilder.put("x", new Integer(in.point.split(",")[0]));
            resultBuilder.put("y", new Integer(in.point.split(",")[1]));
            resultBuilder.put("nestedResource", in.nested);
            if (TestChildResourceWithCustomSerializer.class.isAssignableFrom(clazz)) {
                resultBuilder.put("aShort", ((TestChildResourceWithCustomSerializer) in).number);
            }
            return resultBuilder.build();
        }

        @Override
        public TestResourceWithCustomSerializer transformFrom(Map<String, Object> in) {
            TestResourceWithCustomSerializer obj = null;
            try {
                obj = clazz.newInstance();
            } catch (Exception e) {
                Throwables.propagate(e);
            }
            obj.point = String.format("%d,%d", MoreObjects.firstNonNull(in.get("x"), 0),
                    MoreObjects.firstNonNull(in.get("y"), 0));
            obj.nested = (TestSerializePublicField) in.get("nestedResource");
            if (TestChildResourceWithCustomSerializer.class.isAssignableFrom(clazz)) {
                ((TestChildResourceWithCustomSerializer) obj).number = (Short) in.get("aShort");
            }
            return obj;
        }

        @Override
        public ResourceSchema getResourceSchema() {
            ResourceSchema.Builder builder = ResourceSchema.builderForType(clazz)
                    .addProperty("x", ResourcePropertySchema.of(TypeToken.of(Integer.class)))
                    .addProperty("y", ResourcePropertySchema.of(TypeToken.of(Integer.class)))
                    .addProperty("nestedResource",
                            ResourcePropertySchema.of(TypeToken.of(TestSerializePublicField.class)));
            if (TestChildResourceWithCustomSerializer.class.isAssignableFrom(clazz)) {
                builder.addProperty("aShort", ResourcePropertySchema.of(TypeToken.of(Short.class)));
            }
            return builder.build();
        }
    }

    public static class TestSerializePublicField {
        public String foo = "test";
    }

    public static class TestSerializePrivateField {
        private String foo = "test";
        public String bar = "test";
    }

    public static class TestSerializeAnnotatedPrivateField {
        @ApiResourceProperty
        private String foo = "test";
    }

    public static class TestSerializePublicIgnoredField {
        @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
        public String foo = "test";
        public String bar = "test";
    }
}