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

net.sourceforge.stripes.action.ObjectOutputBuilder Maven / Gradle / Ivy

There is a newer version: 1.7.0-async-beta
Show newest version
/*
 * Copyright 2015 Stripes Framework.
 *
 * 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 net.sourceforge.stripes.action;

import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import net.sourceforge.stripes.util.Log;

/**
 * This abstract class should be implemented by "builders" which take Java
 * objects and convert them into a specific format (such as JavaScript, XML, or
 * JSON). Originally created by using the JavaScript builder which contains
 * functionality for property and class exclusion.
 *
 * @author Rick Grashel
 * @param  Subclass of this object
 */
public abstract class ObjectOutputBuilder< T extends ObjectOutputBuilder> {

    /**
     * Log instance used to log messages.
     */
    private static final Log log = Log.getInstance(ObjectOutputBuilder.class);

    /**
     * Holds the set of classes representing the primitive types in Java.
     */
    static final Set> simpleTypes = new HashSet>();

    /**
     * Holds the set of types that will be skipped over by default.
     */
    static final Set> ignoredTypes = new HashSet>();

    static {
        simpleTypes.add(Byte.TYPE);
        simpleTypes.add(Short.TYPE);
        simpleTypes.add(Integer.TYPE);
        simpleTypes.add(Long.TYPE);
        simpleTypes.add(Float.TYPE);
        simpleTypes.add(Double.TYPE);
        simpleTypes.add(Boolean.TYPE);
        simpleTypes.add(Character.TYPE);

        ignoredTypes.add(Class.class);
    }

    /**
     * Holds the root object which is to be converted to an output format.
     */
    private final Object rootObject;

    /**
     * Holds the (potentially empty) set of user classes that should be skipped
     * over.
     */
    private final Set> excludeClasses;

    /**
     * Holds the (potentially empty) set of properties that should be skipped
     * over.
     */
    private final Set excludeProperties;

    /**
     * Holds an optional user-supplied name for the root property.
     */
    private String rootVariableName = null;

    /**
     * Constructs a new ObjectOutputBuilder to build output for the root object
     * supplied.
     *
     * @param root The root object from which to being translation into
     * JavaScript
     * @param objectsToExclude Zero or more Strings and/or Classes to be
     * excluded from translation.
     */
    public ObjectOutputBuilder(Object root, Object... objectsToExclude) {
        this.rootObject = root;
        this.excludeClasses = new HashSet>();
        this.excludeProperties = new HashSet();

        for (Object object : objectsToExclude) {
            if (object instanceof Class) {
                addClassExclusion((Class) object);
            } else if (object instanceof String) {
                addPropertyExclusion((String) object);
            } else {
                log.warn("Don't know to determine exclusion for objects of type ", object.getClass().getName(), ". You may only pass in instances of Class and/or String.");
            }
        }

        this.excludeClasses.addAll(ignoredTypes);
    }

    /**
     * Adds one or more properties to the list of property to exclude when
     * translating to the formatted output.
     *
     * @param property one or more property names to be excluded
     * @return the ObjectOutputBuilder instance to simplify method chaining
     */
    public final T addPropertyExclusion(String... property) {
        this.excludeProperties.addAll(Arrays.asList(property));
        return (T) this;
    }

    /**
     * Adds one or more properties to the list of properties to exclude when
     * translating to JavaScript.
     *
     * @param clazz one or more classes to exclude
     * @return the JavaScripBuilder instance to simplify method chaining
     */
    public final T addClassExclusion(Class... clazz) {
        this.excludeClasses.addAll(Arrays.asList(clazz));
        return (T) this;
    }

    /**
     * Sets an optional user-supplied root variable name. If set this name will
     * be used by the building when declaring the root variable to which the JS
     * is assigned. If not provided then a randomly generated name will be used.
     *
     * @param rootVariableName the name to use when declaring the root variable
     */
    public void setRootVariableName(final String rootVariableName) {
        this.rootVariableName = rootVariableName;
    }

    /**
     * Returns the name used to declare the root variable to which the built
     * object is assigned.
     *
     * @return The root variable name for the object which is being converted
     */
    public String getRootVariableName() {
        return rootVariableName;
    }

    /**
     * Causes the JavaScriptBuilder to navigate the properties of the supplied
     * object and convert them to JavaScript.
     *
     * @return String a fragment of JavaScript that will define and return the
     * JavaScript equivalent of the Java object supplied to the builder.
     * @throws java.lang.Exception
     */
    public String build() throws Exception {
        Writer writer = new StringWriter();
        build(writer);
        return writer.toString();
    }

    /**
     * Causes the ObjectOutputBuilder to navigate the properties of the supplied
     * object and convert them to the desired format, writing them to the
     * supplied writer as it goes.
     *
     * @param writer Instance of the writer that the converted object should be
     * written to.
     * @throws java.lang.Exception
     */
    public abstract void build(Writer writer) throws Exception;

    /**
     * Returns true if the supplied type should be excluded from conversion,
     * otherwise returns false. A class should be excluded if it is assignable
     * to one of the types listed for exclusion, or, it is an array of such a
     * type.
     *
     * @param type - Class to check to see if it is excluded for this builder.
     * @return Whether or not the passed class is targeted for exclusion by the
     * builder.
     */
    public boolean isExcludedType(Class type) {
        for (Class excludedType : this.excludeClasses) {
            if (excludedType.isAssignableFrom(type)) {
                return true;
            } else if (type.isArray() && excludedType.isAssignableFrom(type.getComponentType())) {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns true if the object is of a type that can be converted to a simple
     * scalar, and false otherwise.
     *
     * @param in Object to check to see if it is a scalar
     * @return Whether or not the passed object is a scalar object.
     */
    public boolean isScalarType(Object in) {
        if (in == null) {
            return true; // Though not strictly scalar, null can be treated as such
        }
        Class type = in.getClass();
        return simpleTypes.contains(type)
                || Number.class.isAssignableFrom(type)
                || String.class.isAssignableFrom(type)
                || Boolean.class.isAssignableFrom(type)
                || Character.class.isAssignableFrom(type)
                || Date.class.isAssignableFrom(type);
    }

    /**
     * Returns the root object being built.
     *
     * @return Root object being built.
     */
    public Object getRootObject() {
        return this.rootObject;
    }
    
    /**
     * Returns the properties that should be excluded from this 
     * object out.
     * 
     * @return Set of excluded properties
     */
    public Set getExcludedProperties() {
        return this.excludeProperties;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy