Added common classes needed by other gson-jackson code.
Modified some logic to make it more maintainable or perform better.
Updated comments and spacing.
Fix another comment.
Moved gson classes from utils to a separate gson project.
Added GsonXxx annotations to mirror jackson annotations.
Removed unneeded dependencies from gson pom.
Removed old GsonMessage class from policy-endpoints.
Removed trailing spaces.
Updated licenses.
Removed more trailing spaces.
Removed unneeded checkstyle suppression file from utils.
Change-Id: I1a285500faeb0a0b6a1467d09b92ecd3cded713e
Issue-ID: POLICY-1428
Signed-off-by: Jim Hahn <jrh3@att.com>
--- /dev/null
+<?xml version="1.0"?>
+<!--
+ ============LICENSE_START=======================================================
+ Copyright (C) 2019 AT&T Technologies. 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.
+
+ SPDX-License-Identifier: Apache-2.0
+ ============LICENSE_END=========================================================
+-->
+
+<!--
+ NOTE: The sole purpose of this supression file is to allow "$" in field and method
+ names so that the gson class tests can verify that those fields are ignored
+ when doing serialization and de-serialization.
+ -->
+
+<!DOCTYPE suppressions PUBLIC
+ "-//Puppy Crawl//DTD Suppressions 1.0//EN"
+ "http://www.puppycrawl.com/dtds/suppressions_1_0.dtd">
+
+<suppressions>
+ <suppress checks="MemberName"
+ files="AdapterTest.java|ClassWalkerTest.java"
+ lines="1-9999"/>
+ <suppress checks="MethodName"
+ files="AdapterTest.java"
+ lines="1-9999"/>
+</suppressions>
--- /dev/null
+<!--
+ ============LICENSE_START=======================================================
+ ONAP Policy Engine - Common Modules
+ ================================================================================
+ Copyright (C) 2018-2019 AT&T Intellectual Property. 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.
+ ============LICENSE_END=========================================================
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onap.policy.common</groupId>
+ <artifactId>common-modules</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>gson</artifactId>
+ <description>Common Utilities</description>
+ <packaging>jar</packaging>
+
+ <properties>
+ <!-- TODO move to top-level or parent -->
+ <jersey.version>2.25.1</jersey.version>
+ <jackson.version>2.9.5</jackson.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-server</artifactId>
+ <version>${jersey.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>3.11.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <!--This plugin's configuration is used to store Eclipse m2e settings
+ only. It has no influence on the Maven build itself. -->
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.jacoco</groupId>
+ <artifactId>
+ jacoco-maven-plugin
+ </artifactId>
+ <versionRange>
+ [0.7.1.201405082137,)
+ </versionRange>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore />
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>onap-java-style</id>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ <phase>process-sources</phase>
+ <configuration>
+ <!-- Use Google Java Style Guide:
+ https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/google_checks.xml
+ with minor changes -->
+ <configLocation>onap-checkstyle/onap-java-style.xml</configLocation>
+ <!-- <sourceDirectory> is needed so that checkstyle ignores the generated sources directory -->
+ <sourceDirectory>${project.build.sourceDirectory}</sourceDirectory>
+ <includeResources>true</includeResources>
+ <includeTestSourceDirectory>true</includeTestSourceDirectory>
+ <includeTestResources>true</includeTestResources>
+ <excludes>
+ </excludes>
+ <suppressionsLocation>${project.basedir}/checkstyle-suppressions.xml</suppressionsLocation>
+ <consoleOutput>true</consoleOutput>
+ <failsOnViolation>true</failsOnViolation>
+ <violationSeverity>warning</violationSeverity>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.onap.oparent</groupId>
+ <artifactId>checkstyle</artifactId>
+ <version>${oparent.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+</project>
* 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.
* ============LICENSE_END=========================================================
*/
-package org.onap.policy.common.endpoints.http.server.internal;
+package org.onap.policy.common.gson;
import com.google.gson.Gson;
import java.io.IOException;
/**
* Provider that serializes and de-serializes JSON via gson.
- *
- * <p>Note: <i>jersey</i> will ignore this class if the maven artifact,
- * <i>jersey-media-json-jackson</i>, is included, regardless of whether it's included
- * directly or indirectly.
*/
@Provider
@Consumes(MediaType.WILDCARD)
/**
* Constructs the object.
- *
+ *
* @param gson the Gson object to be used to serialize and de-serialize
*/
public GsonMessageBodyHandler(Gson gson) {
/**
* Determines if this provider can handle the given media type.
- *
+ *
* @param mediaType the media type of interest
* @return {@code true} if this provider handles the given media type, {@code false}
* otherwise
* ============LICENSE_END=========================================================
*/
-package org.onap.policy.common.utils.gson;
+package org.onap.policy.common.gson;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.annotation;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Mimics Jackson JsonAnyGetter annotation, but used by gson. This requires the gson
+ * object to be configured with the jackson default behaviors (i.e., the associated
+ * JacksonXxx strategy and adapters must be registered with the gson object).
+ */
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface GsonJsonAnyGetter {
+
+}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.annotation;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Mimics Jackson JsonAnySetter annotation, but used by gson. This requires the gson
+ * object to be configured with the jackson default behaviors (i.e., the associated
+ * JacksonXxx strategy and adapters must be registered with the gson object).
+ */
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface GsonJsonAnySetter {
+
+}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.annotation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Mimics Jackson JsonIgnore annotation, but used by gson. This requires the gson object
+ * to be configured with the jackson default behaviors (i.e., the associated JacksonXxx
+ * strategy and adapters must be registered with the gson object).
+ */
+@Retention(RUNTIME)
+@Target({FIELD, METHOD})
+public @interface GsonJsonIgnore {
+
+}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.annotation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Mimics Jackson JsonProperty annotation, but used by gson. This requires the gson object
+ * to be configured with the jackson default behaviors (i.e., the associated JacksonXxx
+ * strategy and adapters must be registered with the gson object).
+ */
+@Retention(RUNTIME)
+@Target({FIELD, METHOD})
+public @interface GsonJsonProperty {
+
+ /**
+ * Property name of this item when placed into a JsonObject.
+ * @return the item's serialized name
+ */
+ String value() default "";
+}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.internal;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.TypeAdapter;
+import com.google.gson.reflect.TypeToken;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.function.Supplier;
+import java.util.regex.Pattern;
+import org.onap.policy.common.gson.annotation.GsonJsonProperty;
+
+/**
+ * Super class of adapters used to serialize and de-serialize an item.
+ */
+public class Adapter {
+
+ /**
+ * Pattern to match valid identifiers.
+ */
+ private static final Pattern VALID_NAME_PAT = Pattern.compile("[a-zA-Z_]\\w*");
+
+ /**
+ * Name of the property within the json structure containing the item.
+ */
+ private final String propName;
+
+ /**
+ * Gson object that will provide the type converter.
+ */
+ private final Gson gson;
+
+ /**
+ * Converter used when reading.
+ */
+ private final ConvInfo reader;
+
+ /**
+ * Converter used when writing, allocated lazily, once an actual type is determined.
+ */
+ private volatile ConvInfo writer = null;
+
+ /**
+ * Name of the item being lifted - used when throwing exceptions.
+ */
+ private final String fullName;
+
+ /**
+ * Constructs the object.
+ *
+ * @param gson Gson object providing type adapters
+ * @param field field used to access the item from within an object
+ */
+ public Adapter(Gson gson, Field field) {
+ this.propName = detmPropName(field);
+ this.reader = new ConvInfo(TypeToken.get(field.getGenericType()));
+ this.gson = gson;
+ this.fullName = getQualifiedName(field);
+
+ field.setAccessible(true);
+ }
+
+ /**
+ * Constructs the object.
+ *
+ * @param gson Gson object providing type adapters
+ * @param accessor method used to access the item from within an object
+ * @param forGetter {@code true} if the name is for a "getter" method, {@code false}
+ * if for a "setter"
+ * @param valueType the class of value on which this operates
+ */
+ public Adapter(Gson gson, Method accessor, boolean forGetter, Type valueType) {
+ this.propName = (forGetter ? detmGetterPropName(accessor) : detmSetterPropName(accessor));
+ this.reader = new ConvInfo(TypeToken.get(valueType));
+ this.gson = gson;
+ this.fullName = getQualifiedName(accessor);
+
+ accessor.setAccessible(true);
+ }
+
+ /**
+ * Converts an object to a json tree.
+ *
+ * @param object the object to be converted
+ * @return a json tree representing the object
+ */
+ @SuppressWarnings("unchecked")
+ public JsonElement toJsonTree(Object object) {
+ // always use a converter for the specific subclass
+ Class<? extends Object> clazz = object.getClass();
+
+ if (writer == null) {
+ // race condition here, but it's ok to overwrite a previous value
+ writer = new ConvInfo(TypeToken.get(clazz));
+ }
+
+ ConvInfo wtr = writer;
+ TypeAdapter<Object> conv =
+ (TypeAdapter<Object>) (wtr.clazz == clazz ? wtr.getConverter() : gson.getAdapter(clazz));
+
+ return conv.toJsonTree(object);
+ }
+
+ /**
+ * Converts a json tree to an object.
+ *
+ * @param tree the tree to be converted
+ * @return the object represented by the tree
+ */
+ public Object fromJsonTree(JsonElement tree) {
+ return reader.getConverter().fromJsonTree(tree);
+ }
+
+ public final String getPropName() {
+ return propName;
+ }
+
+ public final String getFullName() {
+ return fullName;
+ }
+
+ /**
+ * Makes an error message, appending the item's full name to the message prefix.
+ *
+ * @param prefix the message prefix
+ * @return the error message
+ */
+ public String makeError(String prefix) {
+ return (prefix + fullName);
+ }
+
+ /**
+ * Determines if the field is managed by the walker.
+ *
+ * @param field the field to examine
+ * @return {@code true} if the field is managed by the walker, {@code false} otherwise
+ */
+ public static boolean isManaged(Field field) {
+ return VALID_NAME_PAT.matcher(field.getName()).matches();
+ }
+
+ /**
+ * Determines if the method is managed by the walker.
+ *
+ * @param method the method to examine
+ * @return {@code true} if the method is managed by the walker, {@code false}
+ * otherwise
+ */
+ public static boolean isManaged(Method method) {
+ return VALID_NAME_PAT.matcher(method.getName()).matches();
+ }
+
+ /**
+ * Determines the property name of an item within the json structure.
+ *
+ * @param field the item within the object
+ * @return the json property name for the item or {@code null} if the name is invalid
+ */
+ public static String detmPropName(Field field) {
+ // use the serialized name, if specified
+ GsonJsonProperty prop = field.getAnnotation(GsonJsonProperty.class);
+ if (prop != null && !prop.value().isEmpty()) {
+ return prop.value();
+ }
+
+ // no name provided - use it as is
+ return (isManaged(field) ? field.getName() : null);
+ }
+
+ /**
+ * Determines the property name of an item, within the json structure, associated with
+ * a "get" method.
+ *
+ * @param method method to be invoked to get the item within the object
+ * @return the json property name for the item, or {@code null} if the method name is
+ * not valid
+ */
+ public static String detmGetterPropName(Method method) {
+
+ return detmPropNameCommon(method, () -> {
+
+ if (!isManaged(method)) {
+ return null;
+ }
+
+ String name = method.getName();
+
+ if (name.startsWith("get")) {
+ return name.substring(3);
+
+ } else if (name.startsWith("is")) {
+ Class<?> treturn = method.getReturnType();
+
+ if (treturn == boolean.class || treturn == Boolean.class) {
+ return name.substring(2);
+ }
+ }
+
+ // not a valid name for a "getter" method
+ return null;
+ });
+ }
+
+ /**
+ * Determines the property name of an item, within the json structure, associated with
+ * a "set" method.
+ *
+ * @param method method to be invoked to set the item within the object
+ * @return the json property name for the item, or {@code null} if the method name is
+ * not valid
+ */
+ public static String detmSetterPropName(Method method) {
+
+ return detmPropNameCommon(method, () -> {
+
+ if (!isManaged(method)) {
+ return null;
+ }
+
+ String name = method.getName();
+
+ if (name.startsWith("set")) {
+ return name.substring(3);
+ }
+
+ // not a valid name for a "setter" method
+ return null;
+ });
+ }
+
+ /**
+ * Determines the property name of an item within the json structure.
+ *
+ * @param method method to be invoked to get/set the item within the object
+ * @param extractor function to extract the name directly from the method name
+ * @return the json property name for the item, or {@code null} if the method name is
+ * not valid
+ */
+ private static String detmPropNameCommon(Method method, Supplier<String> extractor) {
+
+ // use the property name, if specified
+ GsonJsonProperty propName = method.getAnnotation(GsonJsonProperty.class);
+ if (propName != null && !propName.value().isEmpty()) {
+ return propName.value();
+ }
+
+ // no name provided - must compute it from the method name
+ String name = extractor.get();
+
+ if (name == null || name.isEmpty()) {
+ // nothing left after stripping the prefix - invalid name
+ return null;
+ }
+
+ // translate the first letter to lower-case
+ return name.substring(0, 1).toLowerCase() + name.substring(1);
+ }
+
+ /**
+ * Gets the fully qualified name of a field.
+ *
+ * @param field field whose name is desired
+ * @return the field fully qualified name
+ */
+ public static String getQualifiedName(Field field) {
+ return (field.getDeclaringClass().getName() + "." + field.getName());
+ }
+
+ /**
+ * Gets the fully qualified name of a method.
+ *
+ * @param method method whose name is desired
+ * @return the method's fully qualified name
+ */
+ public static String getQualifiedName(Method method) {
+ return (method.getDeclaringClass().getName() + "." + method.getName());
+ }
+
+ /**
+ * Converter info.
+ */
+ private class ConvInfo {
+
+ /**
+ * Type on which the converter works.
+ */
+ private TypeToken<?> type;
+
+ /**
+ * Class of object on which the converter works.
+ */
+ private Class<?> clazz;
+
+ /**
+ * Converter to use, initialized lazily.
+ */
+ private volatile TypeAdapter<?> conv = null;
+
+ /**
+ * Constructs the object.
+ *
+ * @param type type of object to be converted
+ */
+ public ConvInfo(TypeToken<?> type) {
+ this.type = type;
+ this.clazz = type.getRawType();
+ }
+
+ public final TypeAdapter<?> getConverter() {
+ if (conv == null) {
+ // race condition here, but it's ok to overwrite a previous value
+ this.conv = gson.getAdapter(type);
+ }
+
+ return conv;
+ }
+ }
+}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.internal;
+
+import com.google.gson.JsonParseException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.onap.policy.common.gson.annotation.GsonJsonAnyGetter;
+import org.onap.policy.common.gson.annotation.GsonJsonAnySetter;
+import org.onap.policy.common.gson.annotation.GsonJsonIgnore;
+import org.onap.policy.common.gson.annotation.GsonJsonProperty;
+
+/**
+ * Data populated while walking the hierarchy of a class.
+ */
+public class ClassWalker {
+
+ public static final String ANY_GETTER_MISMATCH_ERR =
+ GsonJsonAnyGetter.class.getSimpleName() + " parameter mismatch for: ";
+
+ public static final String ANY_SETTER_MISMATCH_ERR =
+ GsonJsonAnySetter.class.getSimpleName() + " parameter mismatch for: ";
+
+ public static final String ANY_SETTER_TYPE_ERR =
+ GsonJsonAnySetter.class.getSimpleName() + " first parameter must be a string: ";
+
+ /**
+ * Maps an input property name to an item within the class, where item is one of:
+ * {@link Field}, {@link Method}, or {@code null}. Entries are overwritten as new
+ * items are added.
+ */
+ private final Map<String, Object> inProps = new HashMap<>();
+
+ /**
+ * Maps an output property name to an item within the class, where item is one of:
+ * {@link Field}, {@link Method}, or {@code null}. Entries are overwritten as new
+ * items are added.
+ */
+ private final Map<String, Object> outProps = new HashMap<>();
+
+ /**
+ * Maps a method name to a "get" method. Used when overriding properties associated
+ * with a method.
+ */
+ private final Map<String, Method> getters = new HashMap<>();
+
+ /**
+ * Maps a method name to a "set" method. Used when overriding properties associated
+ * with a method.
+ */
+ private final Map<String, Method> setters = new HashMap<>();
+
+ /**
+ * Method having {@link GsonJsonAnyGetter} annotation. Overwritten as new "any-getters"
+ * are identified.
+ */
+ private Method anyGetter = null;
+
+ /**
+ * Method having {@link GsonJsonAnySetter} annotation. Overwritten as new "any-setters"
+ * are identified.
+ */
+ private Method anySetter = null;
+
+
+ public Method getAnyGetter() {
+ return anyGetter;
+ }
+
+ public Method getAnySetter() {
+ return anySetter;
+ }
+
+ /**
+ * Gets the names of input properties that are not being ignored.
+ *
+ * @return the non-ignored input property names
+ */
+ public List<String> getInNotIgnored() {
+ return getNonNull(inProps);
+ }
+
+ /**
+ * Gets the names of output properties that are not being ignored.
+ *
+ * @return the non-ignored output property names
+ */
+ public List<String> getOutNotIgnored() {
+ return getNonNull(outProps);
+ }
+
+ /**
+ * Gets the property names, associated with a non-null value, from a set of
+ * properties.
+ *
+ * @param props set of properties from which to extract the names
+ * @return the property names having a non-null value
+ */
+ private List<String> getNonNull(Map<String, Object> props) {
+ List<String> lst = new ArrayList<String>(props.size());
+
+ for (Entry<String, Object> ent : props.entrySet()) {
+ if (ent.getValue() != null) {
+ lst.add(ent.getKey());
+ }
+ }
+
+ return lst;
+ }
+
+ /**
+ * Gets the input properties whose values are of the given class.
+ *
+ * @param clazz class of properties to get
+ * @return the input properties of the given class
+ */
+ public <T> List<T> getInProps(Class<T> clazz) {
+ return getProps(clazz, inProps.values());
+ }
+
+ /**
+ * Gets the output properties whose values are of the given class.
+ *
+ * @param clazz class of properties to get
+ * @return the output properties of the given class
+ */
+ public <T> List<T> getOutProps(Class<T> clazz) {
+ return getProps(clazz, outProps.values());
+ }
+
+ /**
+ * Gets the properties whose values are of the given class.
+ *
+ * @param clazz class of properties to get
+ * @param values values from which to select
+ * @return the output properties of the given class
+ */
+ @SuppressWarnings("unchecked")
+ private <T> List<T> getProps(Class<T> clazz, Collection<Object> values) {
+ List<T> lst = new ArrayList<T>(values.size());
+
+ for (Object val : values) {
+ if (val != null && val.getClass() == clazz) {
+ lst.add((T) val);
+ }
+ }
+
+ return lst;
+ }
+
+ /**
+ * Recursively walks a class hierarchy, including super classes and interfaces,
+ * examining each class for various annotations.
+ *
+ * @param clazz class whose hierarchy is to be walked
+ */
+ public void walkClassHierarchy(Class<?> clazz) {
+ if (clazz == Object.class) {
+ return;
+ }
+
+ // walk interfaces first
+ for (Class<?> intfc : clazz.getInterfaces()) {
+ walkClassHierarchy(intfc);
+ }
+
+ // walk superclass next, overwriting previous items
+ Class<?> sup = clazz.getSuperclass();
+ if (sup != null) {
+ walkClassHierarchy(sup);
+ }
+
+ // finally, examine this class, overwriting previous items
+ examine(clazz);
+ }
+
+ /**
+ * Examines a class for annotations, examining fields and then methods.
+ *
+ * @param clazz class to be examined
+ */
+ protected void examine(Class<?> clazz) {
+ for (Field field : clazz.getDeclaredFields()) {
+ examine(field);
+ }
+
+ for (Method method : clazz.getDeclaredMethods()) {
+ examine(method);
+ }
+ }
+
+ /**
+ * Examines a field for annotations.
+ *
+ * @param field field to be examined
+ */
+ protected void examine(Field field) {
+ if (field.isSynthetic()) {
+ return;
+ }
+
+ int mod = field.getModifiers();
+
+ if (Modifier.isStatic(mod)) {
+ // skip static fields
+ return;
+ }
+
+ if (!Modifier.isPublic(mod) && field.getAnnotation(GsonJsonProperty.class) == null) {
+ // private/protected - skip it unless explicitly exposed
+ return;
+ }
+
+ if (Modifier.isTransient(mod) && field.getAnnotation(GsonJsonProperty.class) == null) {
+ // transient - skip it unless explicitly exposed
+ return;
+ }
+
+ String name = Adapter.detmPropName(field);
+ if (name == null) {
+ // invalid name
+ return;
+ }
+
+ // if ignoring, then insert null into the map, otherwise insert the field
+ Field annotField = (field.getAnnotation(GsonJsonIgnore.class) != null ? null : field);
+
+ // a field can be both an input and an output
+
+ inProps.put(name, annotField);
+ outProps.put(name, annotField);
+ }
+
+ /**
+ * Examines a method for annotations.
+ *
+ * @param method method to be examined
+ */
+ protected void examine(Method method) {
+ if (method.isSynthetic()) {
+ return;
+ }
+
+ int mod = method.getModifiers();
+
+ if (Modifier.isStatic(mod)) {
+ // static methods are not exposed
+ return;
+ }
+
+ GsonJsonProperty prop = method.getAnnotation(GsonJsonProperty.class);
+ GsonJsonAnyGetter get = method.getAnnotation(GsonJsonAnyGetter.class);
+ GsonJsonAnySetter set = method.getAnnotation(GsonJsonAnySetter.class);
+
+ if (!Modifier.isPublic(mod) && prop == null && get == null && set == null) {
+ // private/protected methods are not exposed, unless annotated
+ return;
+ }
+
+
+ if (method.getReturnType() == void.class) {
+ // "void" return type - must be a "setter" method
+ if (set == null) {
+ examineSetter(method);
+
+ } else {
+ examineAnySetter(method);
+ }
+
+ } else {
+ // must be a "getter" method
+ if (get == null) {
+ examineGetter(method);
+
+ } else {
+ examineAnyGetter(method);
+ }
+ }
+ }
+
+ /**
+ * Examines a "setter" method.
+ *
+ * @param method method to be examined
+ */
+ private void examineSetter(Method method) {
+ String name = Adapter.detmSetterPropName(method);
+ if (name != null && method.getParameterCount() == 1) {
+ // remove old name mapping, if any
+ Method old = setters.get(method.getName());
+ if (old != null) {
+ inProps.remove(Adapter.detmSetterPropName(old));
+ }
+
+ setters.put(method.getName(), method);
+
+ // if ignoring, then insert null into the map, otherwise insert the method
+ inProps.put(name, (method.getAnnotation(GsonJsonIgnore.class) != null ? null : method));
+ }
+ }
+
+ /**
+ * Examines a "getter" method.
+ *
+ * @param method method to be examined
+ */
+ private void examineGetter(Method method) {
+ String name = Adapter.detmGetterPropName(method);
+ if (name != null && method.getParameterCount() == 0) {
+ // remove old name mapping, if any
+ Method old = getters.get(method.getName());
+ if (old != null) {
+ outProps.remove(Adapter.detmGetterPropName(old));
+ }
+
+ getters.put(method.getName(), method);
+
+ // if ignoring, then insert null into the map, otherwise insert the method
+ outProps.put(name, (method.getAnnotation(GsonJsonIgnore.class) != null ? null : method));
+ }
+ }
+
+ /**
+ * Examines a method having a {@link GsonJsonAnySetter} annotation.
+ *
+ * @param method method to be examined
+ */
+ private void examineAnySetter(Method method) {
+ if (method.getParameterCount() != 2) {
+ throw new JsonParseException(ANY_SETTER_MISMATCH_ERR + getFqdn(method));
+ }
+
+ if (method.getParameterTypes()[0] != String.class) {
+ throw new JsonParseException(ANY_SETTER_TYPE_ERR + getFqdn(method));
+ }
+
+ // if ignoring, then use null, otherwise use the method
+ anySetter = (method.getAnnotation(GsonJsonIgnore.class) != null ? null : method);
+ }
+
+ /**
+ * Examines a method having a {@link GsonJsonAnyGetter} annotation.
+ *
+ * @param method method to be examined
+ */
+ private void examineAnyGetter(Method method) {
+ if (method.getParameterCount() != 0) {
+ throw new JsonParseException(ANY_GETTER_MISMATCH_ERR + getFqdn(method));
+ }
+
+ // if ignoring, then use null, otherwise use the method
+ anyGetter = (method.getAnnotation(GsonJsonIgnore.class) != null ? null : method);
+ }
+
+ /**
+ * Gets the fully qualified name of a method.
+ *
+ * @param method method whose name is desired
+ * @return the fully qualified method name
+ */
+ private String getFqdn(Method method) {
+ return (method.getDeclaringClass().getName() + "." + method.getName());
+ }
+}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.internal;
+
+import com.google.gson.JsonObject;
+
+/**
+ * Super class of all de-serializers.
+ */
+public interface Deserializer {
+
+ String INVOKE_ERR = "cannot invoke method to deserialize: ";
+
+ /**
+ * Gets an value from a tree, converts it, and puts it into a target object.
+ *
+ * @param source tree from which to get the value
+ * @param target where to place the converted value
+ */
+ void getFromTree(JsonObject source, Object target);
+}
* ============LICENSE_END=========================================================
*/
-package org.onap.policy.common.endpoints.http.server.test;
+package org.onap.policy.common.gson;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import javax.ws.rs.core.MediaType;
import org.junit.Before;
import org.junit.Test;
-import org.onap.policy.common.endpoints.http.server.internal.GsonMessageBodyHandler;
+import org.onap.policy.common.gson.GsonMessageBodyHandler;
public class GsonMessageBodyHandlerTest {
private static final String GEN_TYPE = "some-type";
* ============LICENSE_END=========================================================
*/
-package org.onap.policy.common.utils.gson;
+package org.onap.policy.common.gson;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import java.util.TreeMap;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.onap.policy.common.gson.JacksonExclusionStrategy;
public class JacksonExclusionStrategyTest {
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonPrimitive;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import org.junit.Test;
+import org.onap.policy.common.gson.JacksonExclusionStrategy;
+import org.onap.policy.common.gson.annotation.GsonJsonProperty;
+import org.onap.policy.common.gson.internal.Adapter;
+import org.onap.policy.common.gson.internal.DataAdapterFactory.Data;
+import org.onap.policy.common.gson.internal.DataAdapterFactory.DerivedData;
+
+public class AdapterTest {
+ private static final String GET_VALUE_NAME = "getValue";
+ private static final String VALUE_NAME = "value";
+ private static final String MY_NAME = AdapterTest.class.getName();
+
+ private static DataAdapterFactory dataAdapter = new DataAdapterFactory();
+
+ private static Gson gson = new GsonBuilder().registerTypeAdapterFactory(dataAdapter)
+ .setExclusionStrategies(new JacksonExclusionStrategy()).create();
+
+ /*
+ * The remaining fields are just used within the tests.
+ */
+
+ private String value;
+
+ // empty alias - should use field name
+ @GsonJsonProperty("")
+ protected String emptyAlias;
+
+ @GsonJsonProperty("name-with-alias")
+ protected String nameWithAlias;
+
+ protected String unaliased;
+
+ protected String $invalidFieldName;
+
+ private List<Data> listField;
+
+ private Data dataField;
+
+
+ @Test
+ public void testIsManagedField() {
+ assertTrue(Adapter.isManaged(field(VALUE_NAME)));
+
+ assertFalse(Adapter.isManaged(field("$invalidFieldName")));
+ }
+
+ @Test
+ public void testIsManagedMethod() {
+ assertTrue(Adapter.isManaged(mget(GET_VALUE_NAME)));
+
+ assertFalse(Adapter.isManaged(mget("get$InvalidName")));
+ assertFalse(Adapter.isManaged(mset("set$InvalidName")));
+ }
+
+ @Test
+ public void testAdapterField_Converter() {
+ Adapter adapter = new Adapter(gson, field("dataField"));
+
+ // first, write something of type Data
+ dataAdapter.reset();
+ dataField = new Data(300);
+ JsonElement tree = adapter.toJsonTree(dataField);
+ assertEquals("{'id':300}".replace('\'', '"'), tree.toString());
+
+ // now try a subclass
+ dataAdapter.reset();
+ dataField = new DerivedData(300, "three");
+ tree = adapter.toJsonTree(dataField);
+ assertEquals("{'id':300,'text':'three'}".replace('\'', '"'), tree.toString());
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testAdapterField_Converter_List() {
+ listField = DataAdapterFactory.makeList();
+
+ Adapter adapter = new Adapter(gson, field("listField"));
+
+ dataAdapter.reset();
+ JsonElement tree = adapter.toJsonTree(listField);
+ assertTrue(dataAdapter.isDataWritten());
+ assertEquals(DataAdapterFactory.ENCODED_LIST, tree.toString());
+
+ // encode it twice so it uses the cached converter
+ dataAdapter.reset();
+ tree = adapter.toJsonTree(listField);
+ assertTrue(dataAdapter.isDataWritten());
+ assertEquals(DataAdapterFactory.ENCODED_LIST, tree.toString());
+
+ dataAdapter.reset();
+ List<Data> lst2 = (List<Data>) adapter.fromJsonTree(tree);
+ assertTrue(dataAdapter.isDataRead());
+
+ assertEquals(listField.toString(), lst2.toString());
+
+ // decode it twice so it uses the cached converter
+ dataAdapter.reset();
+ lst2 = (List<Data>) adapter.fromJsonTree(tree);
+ assertTrue(dataAdapter.isDataRead());
+
+ assertEquals(listField.toString(), lst2.toString());
+ }
+
+ @Test
+ public void testAdapterMethod_Converter() throws Exception {
+ listField = DataAdapterFactory.makeList();
+
+ Method getter = mget("getMyList");
+
+ Adapter aget = new Adapter(gson, getter, true, getter.getReturnType());
+
+ dataAdapter.reset();
+ JsonElement tree = aget.toJsonTree(listField);
+ assertTrue(dataAdapter.isDataWritten());
+ assertEquals(DataAdapterFactory.ENCODED_LIST, tree.toString());
+
+ Method setter = AdapterTest.class.getDeclaredMethod("setMyList", List.class);
+ Adapter aset = new Adapter(gson, setter, true, setter.getGenericParameterTypes()[0]);
+
+ dataAdapter.reset();
+ @SuppressWarnings("unchecked")
+ List<Data> lst2 = (List<Data>) aset.fromJsonTree(tree);
+ assertTrue(dataAdapter.isDataRead());
+
+ assertEquals(listField.toString(), lst2.toString());
+ }
+
+ @Test
+ public void testGetPropName_testGetFullName_testMakeError() {
+ // test field
+ Adapter adapter = new Adapter(gson, field(VALUE_NAME));
+
+ assertEquals(VALUE_NAME, adapter.getPropName());
+ assertEquals(MY_NAME + ".value", adapter.getFullName());
+
+
+ // test getter
+ adapter = new Adapter(gson, mget(GET_VALUE_NAME), true, String.class);
+
+ assertEquals(VALUE_NAME, adapter.getPropName());
+ assertEquals(MY_NAME + ".getValue", adapter.getFullName());
+
+ assertEquals("hello: " + MY_NAME + ".getValue", adapter.makeError("hello: "));
+
+
+ // test setter
+ adapter = new Adapter(gson, mset("setValue"), false, String.class);
+
+ assertEquals(VALUE_NAME, adapter.getPropName());
+ assertEquals(MY_NAME + ".setValue", adapter.getFullName());
+ }
+
+ @Test
+ public void testToJsonTree() {
+ Adapter adapter = new Adapter(gson, field(VALUE_NAME));
+
+ JsonElement tree = adapter.toJsonTree("hello");
+ assertTrue(tree.isJsonPrimitive());
+ assertEquals("hello", tree.getAsString());
+ }
+
+ @Test
+ public void testFromJsonTree() {
+ Adapter adapter = new Adapter(gson, field(VALUE_NAME));
+
+ assertEquals("world", adapter.fromJsonTree(new JsonPrimitive("world")));
+ }
+
+ @Test
+ public void testDetmPropName() {
+ assertEquals("emptyAlias", Adapter.detmPropName(field("emptyAlias")));
+ assertEquals("name-with-alias", Adapter.detmPropName(field("nameWithAlias")));
+ assertEquals("unaliased", Adapter.detmPropName(field("unaliased")));
+ assertEquals(null, Adapter.detmPropName(field("$invalidFieldName")));
+ }
+
+ @Test
+ public void testDetmGetterPropName() {
+ assertEquals("emptyAlias", Adapter.detmGetterPropName(mget("getEmptyAlias")));
+ assertEquals("get-with-alias", Adapter.detmGetterPropName(mget("getWithAlias")));
+ assertEquals("plain", Adapter.detmGetterPropName(mget("getPlain")));
+ assertEquals("primBool", Adapter.detmGetterPropName(mget("isPrimBool")));
+ assertEquals("boxedBool", Adapter.detmGetterPropName(mget("isBoxedBool")));
+ assertEquals(null, Adapter.detmGetterPropName(mget("isString")));
+ assertEquals(null, Adapter.detmGetterPropName(mget("noGet")));
+ assertEquals(null, Adapter.detmGetterPropName(mget("get")));
+ assertEquals(null, Adapter.detmGetterPropName(mget("get$InvalidName")));
+ }
+
+ @Test
+ public void testDetmSetterPropName() {
+ assertEquals("emptyAlias", Adapter.detmSetterPropName(mset("setEmptyAlias")));
+ assertEquals("set-with-alias", Adapter.detmSetterPropName(mset("setWithAlias")));
+ assertEquals("plain", Adapter.detmSetterPropName(mset("setPlain")));
+ assertEquals(null, Adapter.detmSetterPropName(mset("noSet")));
+ assertEquals(null, Adapter.detmSetterPropName(mset("set")));
+ assertEquals(null, Adapter.detmSetterPropName(mset("set$InvalidName")));
+ }
+
+ @Test
+ public void testGetQualifiedNameField() throws Exception {
+ assertEquals(MY_NAME + ".value", Adapter.getQualifiedName(AdapterTest.class.getDeclaredField(VALUE_NAME)));
+ }
+
+ @Test
+ public void testGetQualifiedNameMethod() throws Exception {
+ assertEquals(MY_NAME + ".getValue", Adapter.getQualifiedName(mget(GET_VALUE_NAME)));
+ }
+
+ /**
+ * Gets a field from this class, by name.
+ *
+ * @param name name of the field to get
+ * @return the field
+ */
+ private Field field(String name) {
+ try {
+ return AdapterTest.class.getDeclaredField(name);
+
+ } catch (SecurityException | NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets a "getter" method from this class, by name.
+ *
+ * @param name name of the method to get
+ * @return the method
+ */
+ private Method mget(String name) {
+ try {
+ return AdapterTest.class.getDeclaredMethod(name);
+
+ } catch (NoSuchMethodException | SecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets a "setter" method from this class, by name.
+ *
+ * @param name name of the method to get
+ * @return the method
+ */
+ private Method mset(String name) {
+ try {
+ return AdapterTest.class.getDeclaredMethod(name, String.class);
+
+ } catch (NoSuchMethodException | SecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /*
+ * The remaining methods are just used within the tests.
+ */
+
+ protected String getValue() {
+ return value;
+ }
+
+ // empty alias - should use method name
+ @GsonJsonProperty("")
+ protected String getEmptyAlias() {
+ return "";
+ }
+
+ @GsonJsonProperty("get-with-alias")
+ protected String getWithAlias() {
+ return "";
+ }
+
+ // no alias, begins with "get"
+ protected String getPlain() {
+ return "";
+ }
+
+ // begins with "is", returns primitive boolean
+ protected boolean isPrimBool() {
+ return true;
+ }
+
+ // begins with "is", returns boxed Boolean
+ protected Boolean isBoxedBool() {
+ return true;
+ }
+
+ // begins with "is", but doesn't return a boolean
+ protected String isString() {
+ return "";
+ }
+
+ // doesn't begin with "get"
+ protected String noGet() {
+ return "";
+ }
+
+ // nothing after "get"
+ protected String get() {
+ return "";
+ }
+
+ // name has a bogus character
+ protected String get$InvalidName() {
+ return "";
+ }
+
+
+ protected void setValue(String text) {
+ // do nothing
+ }
+
+ // empty alias - should use method name
+ @GsonJsonProperty("")
+ protected void setEmptyAlias(String text) {
+ // do nothing
+ }
+
+ @GsonJsonProperty("set-with-alias")
+ protected void setWithAlias(String text) {
+ // do nothing
+ }
+
+ // no alias, begins with "set"
+ protected void setPlain(String text) {
+ // do nothing
+ }
+
+ // doesn't begin with "set"
+ protected void noSet(String text) {
+ // do nothing
+ }
+
+ // nothing after "get"
+ protected void set(String text) {
+ // do nothing
+ }
+
+ // name has a bogus character
+ protected void set$InvalidName(String text) {
+ // do nothing
+ }
+
+ // returns a list
+ protected List<Data> getMyList() {
+ return listField;
+ }
+
+ // accepts a list
+ protected void setMyList(List<Data> newList) {
+ listField = newList;
+ }
+}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.internal;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import com.google.gson.JsonParseException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.gson.annotation.GsonJsonAnyGetter;
+import org.onap.policy.common.gson.annotation.GsonJsonAnySetter;
+import org.onap.policy.common.gson.annotation.GsonJsonIgnore;
+import org.onap.policy.common.gson.annotation.GsonJsonProperty;
+import org.onap.policy.common.gson.internal.Adapter;
+import org.onap.policy.common.gson.internal.ClassWalker;
+
+public class ClassWalkerTest {
+
+ private MyWalker walker;
+
+ /**
+ * Set up.
+ */
+ @Before
+ public void setUp() {
+ walker = new MyWalker();
+ }
+
+ @Test
+ public void testExamineClassOfQ_testExamineField_testExamineInField_testExamineOutField() {
+ walker.walkClassHierarchy(DerivedFromBottom.class);
+
+ assertEquals("[Intfc1, Intfc2, Intfc1, Intfc3, Bottom, DerivedFromBottom]", walker.classes.toString());
+
+ List<String> inFields = walker.getInProps(Field.class).stream().map(field -> field.getName())
+ .collect(Collectors.toList());
+ Collections.sort(inFields);
+ assertEquals("[exposedField, overriddenValue, transField]", inFields.toString());
+
+ List<String> outFields = walker.getInProps(Field.class).stream().map(field -> field.getName())
+ .collect(Collectors.toList());
+ Collections.sort(outFields);
+ assertEquals("[exposedField, overriddenValue, transField]", outFields.toString());
+
+ // should work with interfaces without throwing an NPE
+ walker.walkClassHierarchy(Intfc1.class);
+ }
+
+ @Test
+ public void testHasAnyGetter() {
+ walker.walkClassHierarchy(Object.class);
+ assertNull(walker.getAnyGetter());
+ assertNull(walker.getAnySetter());
+
+ walker.walkClassHierarchy(AnyGetterIgnored.class);
+ assertNull(walker.getAnyGetter());
+ assertNull(walker.getAnySetter());
+
+ walker.walkClassHierarchy(AnyGetterOnly.class);
+ assertNotNull(walker.getAnyGetter());
+ assertNull(walker.getAnySetter());
+ }
+
+ @Test
+ public void testHasAnySetter() {
+ walker.walkClassHierarchy(Object.class);
+ assertNull(walker.getAnySetter());
+ assertNull(walker.getAnyGetter());
+
+ walker.walkClassHierarchy(AnySetterIgnored.class);
+ assertNull(walker.getAnySetter());
+ assertNull(walker.getAnyGetter());
+
+ walker.walkClassHierarchy(AnySetterOnly.class);
+ assertNotNull(walker.getAnySetter());
+ assertNull(walker.getAnyGetter());
+ }
+
+ @Test
+ public void testExamineMethod() {
+ walker.walkClassHierarchy(DerivedFromData.class);
+
+ assertEquals("[Data, DerivedFromData]", walker.classes.toString());
+
+ // ensure all methods were examined
+ Collections.sort(walker.methods);
+ List<String> lst = Arrays.asList("getId", "getValue", "getOnlyOut", "getStatic", "getText", "getTheMap",
+ "getUnserialized", "getValue", "getWithParams", "setExtraParams", "setId", "setMap",
+ "setMapValue", "setMissingParams", "setNonPublic", "setOnlyIn", "setText", "setUnserialized",
+ "setValue", "setValue", "wrongGetPrefix", "wrongSetPrefix");
+ Collections.sort(lst);
+ assertEquals(lst.toString(), walker.methods.toString());
+
+ assertNotNull(walker.getAnyGetter());
+ assertEquals("getTheMap", walker.getAnyGetter().getName());
+
+ List<String> getters = walker.getOutProps(Method.class).stream().map(method -> method.getName())
+ .collect(Collectors.toList());
+ Collections.sort(getters);
+ assertEquals("[getId, getOnlyOut, getValue]", getters.toString());
+
+ assertNotNull(walker.getAnySetter());
+ assertEquals("setMapValue", walker.getAnySetter().getName());
+
+ List<String> setters = walker.getInProps(Method.class).stream().map(method -> method.getName())
+ .collect(Collectors.toList());
+ Collections.sort(setters);
+ assertEquals("[setId, setOnlyIn, setValue]", setters.toString());
+
+ // getter with invalid parameter count
+ assertThatThrownBy(() -> walker.walkClassHierarchy(AnyGetterMismatchParams.class))
+ .isInstanceOf(JsonParseException.class).hasMessage(ClassWalker.ANY_GETTER_MISMATCH_ERR
+ + AnyGetterMismatchParams.class.getName() + ".getTheMap");
+
+ // setter with too few parameters
+ assertThatThrownBy(() -> walker.walkClassHierarchy(AnySetterTooFewParams.class))
+ .isInstanceOf(JsonParseException.class).hasMessage(ClassWalker.ANY_SETTER_MISMATCH_ERR
+ + AnySetterTooFewParams.class.getName() + ".setOverride");
+
+ // setter with too many parameters
+ assertThatThrownBy(() -> walker.walkClassHierarchy(AnySetterTooManyParams.class))
+ .isInstanceOf(JsonParseException.class).hasMessage(ClassWalker.ANY_SETTER_MISMATCH_ERR
+ + AnySetterTooManyParams.class.getName() + ".setOverride");
+
+ // setter with invalid parameter type
+ assertThatThrownBy(() -> walker.walkClassHierarchy(AnySetterInvalidParam.class))
+ .isInstanceOf(JsonParseException.class).hasMessage(ClassWalker.ANY_SETTER_TYPE_ERR
+ + AnySetterInvalidParam.class.getName() + ".setOverride");
+ }
+
+ @Test
+ public void testExamineMethod_AnyGetter() {
+ walker.walkClassHierarchy(AnyGetterOverride.class);
+
+ assertNotNull(walker.getAnyGetter());
+ assertEquals("getOverride", walker.getAnyGetter().getName());
+ }
+
+ @Test
+ public void testExamineMethod_AnySetter() {
+ walker.walkClassHierarchy(AnySetterOverride.class);
+
+ assertNotNull(walker.getAnySetter());
+ assertEquals("setOverride", walker.getAnySetter().getName());
+ }
+
+ @Test
+ public void testGetInNotIgnored_testGetOutNotIgnored() {
+ walker.walkClassHierarchy(DerivedFromData.class);
+
+ assertEquals("[id, onlyIn, text, value]", new TreeSet<>(walker.getInNotIgnored()).toString());
+ assertEquals("[id, onlyOut, text, value]", new TreeSet<>(walker.getOutNotIgnored()).toString());
+ }
+
+ /**
+ * Walker subclass that records items that are examined.
+ */
+ private static class MyWalker extends ClassWalker {
+ private List<String> classes = new ArrayList<>();
+ private List<String> methods = new ArrayList<>();
+
+ @Override
+ protected void examine(Class<?> clazz) {
+ classes.add(clazz.getSimpleName());
+
+ super.examine(clazz);
+ }
+
+ @Override
+ protected void examine(Method method) {
+ if (Adapter.isManaged(method)) {
+ methods.add(method.getName());
+ }
+
+ super.examine(method);
+ }
+ }
+
+ protected static interface Intfc1 {
+ int id = 1000;
+ }
+
+ protected static interface Intfc2 {
+ String text = "intfc2-text";
+ }
+
+ private static interface Intfc3 {
+
+ }
+
+ protected static class Bottom implements Intfc1, Intfc3 {
+ private int id;
+ public String value;
+
+ public String invalid$fieldName;
+
+ @GsonJsonProperty("exposed")
+ private String exposedField;
+
+ @GsonJsonIgnore
+ public int ignored;
+
+ public transient int ignoredTransField;
+
+ @GsonJsonProperty("trans")
+ public transient int transField;
+
+ @GsonJsonIgnore
+ public int getId() {
+ return id;
+ }
+
+ @GsonJsonIgnore
+ public void setId(int id) {
+ this.id = id;
+ }
+ }
+
+ protected static class DerivedFromBottom extends Bottom implements Intfc1, Intfc2 {
+ private String text;
+ protected String anotherValue;
+
+ @GsonJsonProperty("value")
+ public String overriddenValue;
+
+ @GsonJsonIgnore
+ public String getText() {
+ return text;
+ }
+
+ @GsonJsonIgnore
+ public void setText(String text) {
+ this.text = text;
+ }
+ }
+
+ protected static class Data {
+ private int id;
+ private String text;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ // not public, but property provided
+ @GsonJsonProperty("text")
+ protected String getText() {
+ return text;
+ }
+
+ // this will be ignored, because there's already a field by this name
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ // should only show up in the output list
+ public int getOnlyOut() {
+ return 1100;
+ }
+
+ // will be overridden by subclass
+ @GsonJsonProperty("super-value-getter")
+ public String getValue() {
+ return null;
+ }
+
+ // will be overridden by subclass
+ @GsonJsonProperty("super-value-setter")
+ public void setValue(String value) {
+ // do nothing
+ }
+ }
+
+ protected static class DerivedFromData extends Data {
+ // not serialized
+ private String unserialized;
+
+ // overrides private field and public method from Data
+ public String text;
+
+ private Map<String, String> map;
+
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ @GsonJsonAnyGetter
+ public Map<String, String> getTheMap() {
+ return map;
+ }
+
+ @GsonJsonIgnore
+ public void setMap(Map<String, String> map) {
+ this.map = map;
+ }
+
+ @GsonJsonAnySetter
+ public void setMapValue(String key, String value) {
+ if (map == null) {
+ map = new TreeMap<>();
+ }
+
+ map.put(key, value);
+ }
+
+ @GsonJsonIgnore
+ public String getUnserialized() {
+ return unserialized;
+ }
+
+ @GsonJsonIgnore
+ public void setUnserialized(String unserialized) {
+ this.unserialized = unserialized;
+ }
+
+ // should only show up in the input list
+ public void setOnlyIn(int value) {
+ // do nothing
+ }
+
+ // has a param - shouldn't be serialized
+ public int getWithParams(String text) {
+ return 1000;
+ }
+
+ // too few params - shouldn't be serialized
+ public void setMissingParams() {
+ // do nothing
+ }
+
+ // too many params - shouldn't be serialized
+ public void setExtraParams(String text, String moreText) {
+ // do nothing
+ }
+
+ // not public - shouldn't be serialized
+ protected void setNonPublic(String text) {
+ // do nothing
+ }
+
+ // doesn't start with "get"
+ public String wrongGetPrefix() {
+ return null;
+ }
+
+ // doesn't start with "set"
+ public void wrongSetPrefix(String text) {
+ // do nothing
+ }
+
+ // static
+ public static String getStatic() {
+ return null;
+ }
+ }
+
+ /**
+ * The "get" method has an incorrect argument count.
+ */
+ private static class AnyGetterMismatchParams {
+ @GsonJsonAnyGetter
+ public Map<String, String> getTheMap(String arg) {
+ return new TreeMap<>();
+ }
+ }
+
+ /**
+ * Has {@link GsonJsonAnyGetter} method.
+ */
+ private static class AnyGetterOnly {
+ @GsonJsonAnyGetter
+ private Map<String, Integer> getOverride() {
+ return null;
+ }
+ }
+
+ /**
+ * Has {@link GsonJsonAnyGetter} method, but it's ignored.
+ */
+ private static class AnyGetterIgnored {
+ @GsonJsonAnyGetter
+ @GsonJsonIgnore
+ private Map<String, Integer> getOverride() {
+ return null;
+ }
+ }
+
+ /**
+ * Has {@link GsonJsonAnySetter} method.
+ */
+ private static class AnySetterOnly {
+ @GsonJsonAnySetter
+ private void setOverride(String key, int value) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Has {@link GsonJsonAnySetter} method, but it's ignored.
+ */
+ private static class AnySetterIgnored {
+ @GsonJsonAnySetter
+ @GsonJsonIgnore
+ private void setOverride(String key, int value) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Has {@link GsonJsonAnyGetter} method that overrides the super class' method.
+ */
+ private static class AnyGetterOverride extends DerivedFromData {
+ private Map<String, Integer> overMap;
+
+ @GsonJsonAnyGetter
+ private Map<String, Integer> getOverride() {
+ return overMap;
+ }
+ }
+
+ /**
+ * Has {@link GsonJsonAnySetter} method that overrides the super class' method.
+ */
+ private static class AnySetterOverride extends DerivedFromData {
+ private Map<String, Integer> overMap;
+
+ @GsonJsonAnySetter
+ private void setOverride(String key, int value) {
+ if (overMap == null) {
+ overMap = new TreeMap<>();
+ }
+
+ overMap.put(key, value);
+ }
+ }
+
+ /**
+ * Has {@link GsonJsonAnySetter} method with too few parameters.
+ */
+ private static class AnySetterTooFewParams extends DerivedFromData {
+ @GsonJsonAnySetter
+ public void setOverride(String key) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Has {@link GsonJsonAnySetter} method with too few parameters.
+ */
+ private static class AnySetterTooManyParams extends DerivedFromData {
+ @GsonJsonAnySetter
+ public void setOverride(String key, int value, String anotherValue) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Has {@link GsonJsonAnySetter} method whose first argument type is incorrect.
+ */
+ private static class AnySetterInvalidParam extends DerivedFromData {
+ @GsonJsonAnySetter
+ public void setOverride(Integer key, String value) {
+ // do nothing
+ }
+ }
+}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.gson.internal;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Factory used with test Data.
+ */
+public class DataAdapterFactory implements TypeAdapterFactory {
+
+ /**
+ * Output of {@link #makeList()}, encoded as json.
+ */
+ public static final String ENCODED_LIST = "[{'id':100},{'id':101}]".replace('\'', '"');
+
+ /**
+ * Output of {@link #makeMap()}, encoded as json.
+ */
+ public static final String ENCODED_MAP = "'data-100':{'id':100},'data-101':{'id':101}".replace('\'', '"');
+
+ /**
+ * Object handled by this factory.
+ */
+ public static class Data {
+ private int id;
+
+ public Data() {
+ super();
+ }
+
+ public Data(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "Data [id=" + id + "]";
+ }
+ }
+
+ /**
+ * Object derived from Data.
+ */
+ public static class DerivedData extends Data {
+ private String text;
+
+ public DerivedData() {
+ super();
+ }
+
+ public DerivedData(int id, String text) {
+ super(id);
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return "DerivedData [text=" + text + ", toString()=" + super.toString() + "]";
+ }
+ }
+
+ /**
+ * Set to {@code true} when {@link #write(JsonWriter, Data)} has been invoked.
+ */
+ private boolean dataWritten = false;
+
+ /**
+ * Set to {@code true} when {@link #read(JsonReader)} has been invoked.
+ */
+ private boolean dataRead = false;
+
+ /**
+ * Clears the flags that indicate that "read" or "write" has been invoked.
+ */
+ public void reset() {
+ dataWritten = true;
+ dataRead = true;
+ }
+
+ public boolean isDataWritten() {
+ return dataWritten;
+ }
+
+ public boolean isDataRead() {
+ return dataRead;
+ }
+
+ /**
+ * Makes a list of Data.
+ *
+ * @return a new list of Data
+ */
+ public static List<Data> makeList() {
+ List<Data> listField = new ArrayList<>();
+
+ listField.add(new Data(100));
+ listField.add(new Data(101));
+
+ return listField;
+ }
+
+ /**
+ * Makes an array of Data.
+ *
+ * @return a new array of Data
+ */
+ public static JsonArray makeArray() {
+ JsonArray arr = new JsonArray();
+
+ for (Data data : makeList()) {
+ JsonObject json = new JsonObject();
+ json.addProperty("id", data.getId());
+ arr.add(json);
+ }
+
+ return arr;
+ }
+
+ /**
+ * Makes a map of Data.
+ *
+ * @return a new map of Data
+ */
+ public static Map<String, List<Data>> makeMap() {
+ Map<String, List<Data>> map = new TreeMap<>();
+
+ for (Data data : makeList()) {
+ map.put("data-" + data.getId(), Arrays.asList(data));
+ }
+
+ return map;
+ }
+
+ /**
+ * Adds Data objects to a tree, mirroring {@link #makeMap()}.
+ *
+ * @param tree tree into which objects are to be added
+ */
+ public static void addToObject(JsonObject tree) {
+ for (JsonElement ent : makeArray()) {
+ JsonObject obj = ent.getAsJsonObject();
+ JsonArray arr = new JsonArray();
+ arr.add(obj);
+ tree.add("data-" + obj.get("id").getAsString(), arr);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
+ if (type.getRawType() == Data.class) {
+ return (TypeAdapter<T>) new DataTypeAdapter(gson.getDelegateAdapter(this, TypeToken.get(Data.class)),
+ gson.getAdapter(JsonElement.class));
+ }
+
+ if (type.getRawType() == DerivedData.class) {
+ return (TypeAdapter<T>) new DerivedDataTypeAdapter(
+ gson.getDelegateAdapter(this, TypeToken.get(DerivedData.class)),
+ gson.getAdapter(JsonElement.class));
+ }
+
+ return null;
+ }
+
+ /**
+ * Adapter for "Data".
+ */
+ private class DataTypeAdapter extends TypeAdapter<Data> {
+ private TypeAdapter<Data> delegate;
+ private TypeAdapter<JsonElement> elementAdapter;
+
+ /**
+ * Constructs the object.
+ *
+ * @param delegate delegate adapter
+ * @param elementAdapter element adapter
+ */
+ public DataTypeAdapter(TypeAdapter<Data> delegate, TypeAdapter<JsonElement> elementAdapter) {
+ this.delegate = delegate;
+ this.elementAdapter = elementAdapter;
+ }
+
+ @Override
+ public void write(JsonWriter out, Data data) throws IOException {
+ dataWritten = true;
+
+ JsonElement tree = delegate.toJsonTree(data);
+
+ if (tree.isJsonObject()) {
+ JsonObject jsonObj = tree.getAsJsonObject();
+ jsonObj.addProperty("id", data.getId());
+ }
+
+ elementAdapter.write(out, tree);
+ }
+
+ @Override
+ public Data read(JsonReader in) throws IOException {
+ dataRead = true;
+
+ JsonElement tree = elementAdapter.read(in);
+ Data data = delegate.fromJsonTree(tree);
+
+ if (tree.isJsonObject()) {
+ JsonObject jsonObj = tree.getAsJsonObject();
+ data.setId(jsonObj.get("id").getAsInt());
+ }
+
+ return data;
+ }
+ }
+ /**
+ * Adapter for "DerivedData".
+ */
+ private class DerivedDataTypeAdapter extends TypeAdapter<DerivedData> {
+ private TypeAdapter<DerivedData> delegate;
+ private TypeAdapter<JsonElement> elementAdapter;
+
+ /**
+ * Constructs the object.
+ *
+ * @param delegate delegate adapter
+ * @param elementAdapter element adapter
+ */
+ public DerivedDataTypeAdapter(TypeAdapter<DerivedData> delegate, TypeAdapter<JsonElement> elementAdapter) {
+ this.delegate = delegate;
+ this.elementAdapter = elementAdapter;
+ }
+
+ @Override
+ public void write(JsonWriter out, DerivedData data) throws IOException {
+ dataWritten = true;
+
+ JsonElement tree = delegate.toJsonTree(data);
+
+ if (tree.isJsonObject()) {
+ JsonObject jsonObj = tree.getAsJsonObject();
+ jsonObj.addProperty("id", data.getId());
+ jsonObj.addProperty("text", data.getText());
+ }
+
+ elementAdapter.write(out, tree);
+ }
+
+ @Override
+ public DerivedData read(JsonReader in) throws IOException {
+ dataRead = true;
+
+ JsonElement tree = elementAdapter.read(in);
+ DerivedData data = delegate.fromJsonTree(tree);
+
+ if (tree.isJsonObject()) {
+ JsonObject jsonObj = tree.getAsJsonObject();
+ data.setId(jsonObj.get("id").getAsInt());
+ data.setText(jsonObj.get("text").getAsString());
+ }
+
+ return data;
+ }
+ }
+}
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.onap.policy.common</groupId>
+ <artifactId>gson</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
<dependency>
<groupId>org.onap.policy.common</groupId>
<artifactId>utils</artifactId>
import java.lang.reflect.Type;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
-import org.onap.policy.common.endpoints.http.server.internal.GsonMessageBodyHandler;
+import org.onap.policy.common.gson.GsonMessageBodyHandler;
/**
* GsonMessageBodyHandler that tracks activities.
-<!--
- ============LICENSE_START=======================================================
- ONAP policy
+<!--
+ ============LICENSE_START=======================================================
+ ONAP policy
================================================================================
- Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ Copyright (C) 2017-2019 AT&T Intellectual Property. 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.
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.
- ============LICENSE_END=========================================================
+ ============LICENSE_END=========================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<staging.path>content/repositories/staging/</staging.path>
<!-- sonar/jacoco overrides -->
- <!-- Overriding oparent default sonar/jacoco settings Combine all
+ <!-- Overriding oparent default sonar/jacoco settings Combine all
our reports into one file shared across sub-modules -->
<sonar.jacoco.reportPath>${project.basedir}/../target/code-coverage/jacoco-ut.exec</sonar.jacoco.reportPath>
<sonar.jacoco.itReportPath>${project.basedir}/../target/code-coverage/jacoco-it.exec</sonar.jacoco.itReportPath>
<module>capabilities</module>
<module>utils-test</module>
<module>utils</module>
+ <module>gson</module>
<module>common-logging</module>
<module>common-parameters</module>
<module>integrity-audit</module>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<configuration>
- <!-- Note: This exclusion list should match <sonar.exclusions>
+ <!-- Note: This exclusion list should match <sonar.exclusions>
property above -->
<excludes>
<exclude>**/gen/**</exclude>
</excludes>
</configuration>
<executions>
- <!-- Prepares the property pointing to the JaCoCo
- runtime agent which is passed as VM argument when Maven the Surefire plugin
+ <!-- Prepares the property pointing to the JaCoCo
+ runtime agent which is passed as VM argument when Maven the Surefire plugin
is executed. -->
<execution>
<id>pre-unit-test</id>
<destFile>${sonar.jacoco.reportPath}</destFile>
</configuration>
</execution>
- <!-- Ensures that the code coverage report for unit
+ <!-- Ensures that the code coverage report for unit
tests is created after unit tests have been run. -->
<execution>
<id>post-unit-test</id>