All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osgi.dto.DTO Maven / Gradle / Ivy

There is a newer version: 1.9.22.1
Show newest version
/*
 * Copyright (c) OSGi Alliance (2012, 2020). 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 org.osgi.dto;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Super type for Data Transfer Objects.
 * 

* A Data Transfer Object (DTO) is easily serializable having only public fields * of primitive types and their wrapper classes, String, enums, Version, and * DTOs. List, Set, Map, and array aggregates may also be used. The aggregates * must only hold objects of the listed types or aggregates. The types for Map * keys are limited to primitive wrapper classes, String, enums, and Version. *

* The object graph from a Data Transfer Object must be a tree to simplify * serialization and deserialization. * * @author $Id: ffcb6416b152127a4c3fdca52426cacbe2f13a58 $ * @NotThreadSafe */ public abstract class DTO { /** * Return a string representation of this DTO suitable for use when * debugging. *

* The format of the string representation is not specified and subject to * change. * * @return A string representation of this DTO suitable for use when * debugging. */ @Override public String toString() { return appendValue(new StringBuilder(), new IdentityHashMap(), "#", this).toString(); } /** * Append the specified DTO's string representation to the specified * StringBuilder. * * @param result StringBuilder to which the string representation is * appended. * @param objectRefs References to "seen" objects. * @param refpath The reference path of the specified DTO. * @param dto The DTO whose string representation is to be appended. * @return The specified StringBuilder. */ private static StringBuilder appendDTO(final StringBuilder result, final Map objectRefs, final String refpath, final DTO dto) { result.append('{'); String delim = ""; for (Field field : dto.getClass().getFields()) { if (Modifier.isStatic(field.getModifiers())) { continue; } result.append(delim); final String name = field.getName(); appendString(result, name); result.append(':'); Object value = null; try { value = field.get(dto); } catch (IllegalAccessException e) { // use null value; } appendValue(result, objectRefs, refpath + "/" + name, value); delim = ", "; } result.append('}'); return result; } /** * Append the specified value's string representation to the specified * StringBuilder. *

* This method handles cycles in the object graph, using path-based * references, even though the specification requires the object graph from * a DTO to be a tree. * * @param result StringBuilder to which the string representation is * appended. * @param objectRefs References to "seen" objects. * @param refpath The reference path of the specified value. * @param value The object whose string representation is to be appended. * @return The specified StringBuilder. */ private static StringBuilder appendValue(final StringBuilder result, final Map objectRefs, final String refpath, final Object value) { if (value == null) { return result.append("null"); } // Simple Java types if (value instanceof String || value instanceof Character) { return appendString(result, compress(value.toString())); } if (value instanceof Number || value instanceof Boolean) { return result.append(value.toString()); } if (value instanceof Enum) { return appendString(result, ((Enum< ? >) value).name()); } if ("org.osgi.framework.Version".equals(value.getClass().getName())) { return appendString(result, value.toString()); } // Complex types final String path = objectRefs.get(value); if (path != null) { result.append("{\"$ref\":"); appendString(result, path); result.append('}'); return result; } objectRefs.put(value, refpath); if (value instanceof DTO) { return appendDTO(result, objectRefs, refpath, (DTO) value); } if (value instanceof Map) { return appendMap(result, objectRefs, refpath, (Map< ? , ? >) value); } if (value instanceof List || value instanceof Set) { return appendIterable(result, objectRefs, refpath, (Iterable< ? >) value); } if (value.getClass().isArray()) { return appendArray(result, objectRefs, refpath, value); } return appendString(result, compress(value.toString())); } /** * Append the specified array's string representation to the specified * StringBuilder. * * @param result StringBuilder to which the string representation is * appended. * @param objectRefs References to "seen" objects. * @param refpath The reference path of the specified array. * @param array The array whose string representation is to be appended. * @return The specified StringBuilder. */ private static StringBuilder appendArray(final StringBuilder result, final Map objectRefs, final String refpath, final Object array) { result.append('['); final int length = Array.getLength(array); for (int i = 0; i < length; i++) { if (i > 0) { result.append(','); } appendValue(result, objectRefs, refpath + "/" + i, Array.get(array, i)); } result.append(']'); return result; } /** * Append the specified iterable's string representation to the specified * StringBuilder. * * @param result StringBuilder to which the string representation is * appended. * @param objectRefs References to "seen" objects. * @param refpath The reference path of the specified list. * @param iterable The iterable whose string representation is to be * appended. * @return The specified StringBuilder. */ private static StringBuilder appendIterable(final StringBuilder result, final Map objectRefs, final String refpath, final Iterable< ? > iterable) { result.append('['); int i = 0; for (Object item : iterable) { if (i > 0) { result.append(','); } appendValue(result, objectRefs, refpath + "/" + i, item); i++; } result.append(']'); return result; } /** * Append the specified map's string representation to the specified * StringBuilder. * * @param result StringBuilder to which the string representation is * appended. * @param objectRefs References to "seen" objects. * @param refpath The reference path of the specified map. * @param map The map whose string representation is to be appended. * @return The specified StringBuilder. */ private static StringBuilder appendMap(final StringBuilder result, final Map objectRefs, final String refpath, final Map< ? , ? > map) { result.append('{'); String delim = ""; for (Map.Entry< ? , ? > entry : map.entrySet()) { result.append(delim); final String name = String.valueOf(entry.getKey()); appendString(result, name); result.append(':'); final Object value = entry.getValue(); appendValue(result, objectRefs, refpath + "/" + name, value); delim = ", "; } result.append('}'); return result; } /** * Append the specified string to the specified StringBuilder. * * @param result StringBuilder to which the string is appended. * @param string The string to be appended. * @return The specified StringBuilder. */ private static StringBuilder appendString(final StringBuilder result, final CharSequence string) { result.append('"'); int i = result.length(); result.append(string); while (i < result.length()) { // escape if necessary char c = result.charAt(i); if ((c == '"') || (c == '\\')) { result.insert(i, '\\'); i = i + 2; continue; } if (c < 0x20) { result.insert(i + 1, Integer.toHexString(c | 0x10000)); result.replace(i, i + 2, "\\u"); i = i + 6; continue; } i++; } result.append('"'); return result; } private static final int MAX_LENGTH = 100; /** * Compress, in length, the specified string. * * @param in The string to potentially compress. * @return The string compressed, if necessary. */ private static CharSequence compress(final CharSequence in) { final int length = in.length(); if (length <= MAX_LENGTH) { return in; } StringBuilder result = new StringBuilder(MAX_LENGTH) .append(in, 0, MAX_LENGTH / 2 - 3) .append('.') .append('.') .append('.') .append(in, length - (MAX_LENGTH / 2), length); return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy