Example usage for com.fasterxml.jackson.core JsonGenerator writeStringField

List of usage examples for com.fasterxml.jackson.core JsonGenerator writeStringField

Introduction

In this page you can find the example usage for com.fasterxml.jackson.core JsonGenerator writeStringField.

Prototype

public void writeStringField(String fieldName, String value) throws IOException, JsonGenerationException 

Source Link

Document

Convenience method for outputting a field entry ("member") that has a String value.

Usage

From source file:org.apache.olingo.server.core.serializer.json.ODataJsonSerializer.java

private void writeExpandedStreamProperty(ExpandOption expand, String propertyName, EdmProperty edmProperty,
        Linked linked, ExpandItem expandAll, JsonGenerator json)
        throws SerializerException, DecoderException, IOException {
    final ExpandItem innerOptions = ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
    if (innerOptions != null || expandAll != null) {
        if (constants instanceof Constantsv00) {
            throw new SerializerException("Expand not supported for Stream Property Type!",
                    SerializerException.MessageKeys.UNSUPPORTED_OPERATION_TYPE, "expand",
                    edmProperty.getName());
        }/*w  ww .j  av  a 2  s  . c  o m*/
        Property property = null;
        if (linked instanceof Entity) {
            Entity entity = (Entity) linked;
            property = (Property) entity.getProperty(propertyName);
        } else if (linked instanceof ComplexValue) {
            List<Property> properties = ((ComplexValue) linked).getValue();
            for (Property prop : properties) {
                if (prop.getName().equals(propertyName)) {
                    property = prop;
                    break;
                }
            }
        }

        if ((property == null || property.isNull()) && edmProperty.isNullable() == Boolean.FALSE) {
            throw new SerializerException("Non-nullable property not present!",
                    SerializerException.MessageKeys.MISSING_PROPERTY, edmProperty.getName());
        }
        Link link = (Link) property.getValue();
        Property stream = link.getInlineEntity().getProperty(propertyName);
        Base64 decoder = new Base64(true);
        byte[] decodedBytes = (byte[]) decoder.decode(stream.getValue());
        json.writeStringField(propertyName, new String(decodedBytes));
    }
}

From source file:de.fraunhofer.iosb.ilt.sta.serialize.EntitySerializer.java

@Override
public void serialize(Entity entity, JsonGenerator gen, SerializerProvider serializers)
        throws IOException, JsonProcessingException {
    gen.writeStartObject();//w  ww.  j a va2s.co m
    try {
        BasicBeanDescription beanDescription = serializers.getConfig()
                .introspect(serializers.constructType(entity.getClass()));
        List<BeanPropertyDefinition> properties = beanDescription.findProperties();
        for (BeanPropertyDefinition property : properties) {
            // 0. check if it should be serialized
            if (selectedProperties != null) {
                if (!selectedProperties.contains(property.getName())) {
                    continue;
                }
            }
            // 1. is it a NavigableElement?
            if (NavigableElement.class.isAssignableFrom(property.getAccessor().getRawType())) {
                Object rawValue = property.getAccessor().getValue(entity);
                if (rawValue != null) {
                    NavigableElement value = (NavigableElement) rawValue;
                    // If navigation link set, output navigation link.
                    if (value.getNavigationLink() != null && !value.getNavigationLink().isEmpty()) {
                        gen.writeFieldName(property.getName() + "@iot.navigationLink");
                        gen.writeString(value.getNavigationLink());
                    }
                    // If object should not be exported, skip any further processing.
                    if (!value.isExportObject()) {
                        continue;
                    }
                }
            }
            // 2. check if property has CustomSerialization annotation -> use custom serializer
            Annotation annotation = property.getAccessor().getAnnotation(CustomSerialization.class);
            if (annotation != null) {
                serializeFieldCustomized(entity, gen, property, properties, (CustomSerialization) annotation);
            } else {
                serializeField(entity, gen, serializers, beanDescription, property);
            }
            // 3. check if property is EntitySet than eventually write count
            if (EntitySet.class.isAssignableFrom(property.getAccessor().getRawType())) {
                Object rawValue = property.getAccessor().getValue(entity);
                if (rawValue != null) {
                    EntitySet set = (EntitySet) rawValue;
                    long count = set.getCount();
                    if (count >= 0) {
                        gen.writeNumberField(property.getName() + "@iot.count", count);
                    }
                    String nextLink = set.getNextLink();
                    if (nextLink != null) {
                        gen.writeStringField(property.getName() + "@iot.nextLink", nextLink);
                    }
                }
            }
        }
    } catch (Exception e) {
        LOGGER.error("could not serialize Entity", e);
        throw new IOException("could not serialize Entity", e);
    } finally {
        gen.writeEndObject();
    }
}

From source file:net.solarnetwork.web.support.JSONView.java

private void writeJsonValue(JsonGenerator json, String key, Object val, PropertyEditorRegistrar registrar)
        throws JsonGenerationException, IOException {
    if (val instanceof Collection<?> || (val != null && val.getClass().isArray())) {
        Collection<?> col;// w  w  w.  j  a va 2s. co  m
        if (val instanceof Collection<?>) {
            col = (Collection<?>) val;
        } else if (!val.getClass().getComponentType().isPrimitive()) {
            col = Arrays.asList((Object[]) val);
        } else {
            // damn you, primitives
            col = getPrimitiveCollection(val);
        }
        if (key != null) {
            json.writeFieldName(key);
        }
        json.writeStartArray();
        for (Object colObj : col) {
            writeJsonValue(json, null, colObj, registrar);
        }

        json.writeEndArray();
    } else if (val instanceof Map<?, ?>) {
        if (key != null) {
            json.writeFieldName(key);
        }
        json.writeStartObject();
        for (Map.Entry<?, ?> me : ((Map<?, ?>) val).entrySet()) {
            Object propName = me.getKey();
            if (propName == null) {
                continue;
            }
            writeJsonValue(json, propName.toString(), me.getValue(), registrar);
        }
        json.writeEndObject();
    } else if (val instanceof Double) {
        if (key == null) {
            json.writeNumber((Double) val);
        } else {
            json.writeNumberField(key, (Double) val);
        }
    } else if (val instanceof Integer) {
        if (key == null) {
            json.writeNumber((Integer) val);
        } else {
            json.writeNumberField(key, (Integer) val);
        }
    } else if (val instanceof Short) {
        if (key == null) {
            json.writeNumber(((Short) val).intValue());
        } else {
            json.writeNumberField(key, ((Short) val).intValue());
        }
    } else if (val instanceof Float) {
        if (key == null) {
            json.writeNumber((Float) val);
        } else {
            json.writeNumberField(key, (Float) val);
        }
    } else if (val instanceof Long) {
        if (key == null) {
            json.writeNumber((Long) val);
        } else {
            json.writeNumberField(key, (Long) val);
        }
    } else if (val instanceof Boolean) {
        if (key == null) {
            json.writeBoolean((Boolean) val);
        } else {
            json.writeBooleanField(key, (Boolean) val);
        }
    } else if (val instanceof String) {
        if (key == null) {
            json.writeString((String) val);
        } else {
            json.writeStringField(key, (String) val);
        }
    } else {
        // create a JSON object from bean properties
        if (getPropertySerializerRegistrar() != null && val != null) {
            // try whole-bean serialization first
            Object o = getPropertySerializerRegistrar().serializeProperty(key, val.getClass(), val, val);
            if (o != val) {
                if (o != null) {
                    writeJsonValue(json, key, o, registrar);
                }
                return;
            }
        }
        generateJavaBeanObject(json, key, val, registrar);
    }
}

From source file:com.googlecode.jmxtrans.model.output.StackdriverWriter.java

/**
 * Take query results, make a JSON String
 * //from www . jav  a2  s .  com
 * @param results List of Result objects
 * @return a String containing a JSON message, or null if there are no values to report
 * 
 * @throws IOException if there is some problem generating the JSON, should be uncommon
 */
private String getGatewayMessage(final List<Result> results) throws IOException {
    int valueCount = 0;
    Writer writer = new StringWriter();
    JsonGenerator g = jsonFactory.createGenerator(writer);
    g.writeStartObject();
    g.writeNumberField("timestamp", System.currentTimeMillis() / 1000);
    g.writeNumberField("proto_version", STACKDRIVER_PROTOCOL_VERSION);
    g.writeArrayFieldStart("data");

    List<String> typeNames = this.getTypeNames();

    for (Result metric : results) {
        Map<String, Object> values = metric.getValues();
        if (values != null) {
            for (Entry<String, Object> entry : values.entrySet()) {
                if (isNumeric(entry.getValue())) {
                    // we have a numeric value, write a value into the message

                    StringBuilder nameBuilder = new StringBuilder();

                    // put the prefix if set
                    if (this.prefix != null) {
                        nameBuilder.append(prefix);
                        nameBuilder.append(".");
                    }

                    // put the class name or its alias if available
                    if (!metric.getKeyAlias().isEmpty()) {
                        nameBuilder.append(metric.getKeyAlias());

                    } else {
                        nameBuilder.append(metric.getClassName());
                    }

                    // Wildcard "typeNames" substitution
                    String typeName = com.googlecode.jmxtrans.model.naming.StringUtils
                            .cleanupStr(TypeNameValuesStringBuilder.getDefaultBuilder().build(typeNames,
                                    metric.getTypeName()));
                    if (typeName != null && typeName.length() > 0) {
                        nameBuilder.append(".");
                        nameBuilder.append(typeName);
                    }

                    // add the attribute name
                    nameBuilder.append(".");
                    nameBuilder.append(metric.getAttributeName());

                    // put the value name if it differs from the attribute name
                    if (!entry.getKey().equals(metric.getAttributeName())) {
                        nameBuilder.append(".");
                        nameBuilder.append(entry.getKey());
                    }

                    // check for Float/Double NaN since these will cause the message validation to fail 
                    if (entry.getValue() instanceof Float && ((Float) entry.getValue()).isNaN()) {
                        logger.info("Metric value for " + nameBuilder.toString() + " is NaN, skipping");
                        continue;
                    }

                    if (entry.getValue() instanceof Double && ((Double) entry.getValue()).isNaN()) {
                        logger.info("Metric value for " + nameBuilder.toString() + " is NaN, skipping");
                        continue;
                    }

                    valueCount++;
                    g.writeStartObject();

                    g.writeStringField("name", nameBuilder.toString());

                    g.writeNumberField("value", Double.valueOf(entry.getValue().toString()));

                    // if the metric is attached to an instance, include that in the message
                    if (instanceId != null && !instanceId.isEmpty()) {
                        g.writeStringField("instance", instanceId);
                    }
                    g.writeNumberField("collected_at", metric.getEpoch() / 1000);
                    g.writeEndObject();
                }
            }
        }
    }

    g.writeEndArray();
    g.writeEndObject();
    g.flush();
    g.close();

    // return the message if there are any values to report
    if (valueCount > 0) {
        return writer.toString();
    } else {
        return null;
    }
}

From source file:org.n52.tamis.core.json.serialize.processes.execute.ExtendedExecuteHttpPostBodySerializer.java

@Override
public void serialize(Execute_HttpPostBody executeBody_short, JsonGenerator jsonGenerator,
        SerializerProvider serProvider) throws IOException, JsonProcessingException {

    logger.info("Start serialization of execute HTTP POST input body \"{}\"", executeBody_short);

    /*/*from   w  w w  .  ja v a  2  s . c  om*/
     * the structure of the target JSON body looks like:
     * 
     * {
    "Execute": {
      "Identifier": "org.n52.tamis.algorithm.interpolation",
      "Input": [
    {
        "Input": [
            {
                "Reference": {
                    "_href": "http://fluggs.wupperverband.de/sos2/service?service=SOS&request=GetObservation&version=2.0.0&offering=Zeitreihen_2m_Tiefe&observedProperty=Grundwasserstand&responseFormat=http%3A//www.opengis.net/om/2.0",
                    "_mimeType": "application/om+xml; version=2.0",
                    "_schema": "http://schemas.opengis.net/om/2.0/observation.xsd"
                },
                "_id": "gw1"
            },
            {
                "Reference": {
                    "_href": "http://fluggs.wupperverband.de/sos2/service?service=SOS&request=GetObservation&version=2.0.0&offering=Zeitreihen_2m_Tiefe&observedProperty=Sohlenwasserdruck&responseFormat=http%3A//www.opengis.net/om/2.0",
                    "_mimeType": "application/om+xml; version=2.0",
                    "_schema": "http://schemas.opengis.net/om/2.0/observation.xsd"
                },
                "_id": "swd1"
            }
        ],
        "_id": "input-variables"
    },
    {
        "Data": {
            "_mimeType": "text/xml",
            "_schema": "http://schemas.opengis.net/gml/3.2.1/base/feature.xsd",
            "__text": "<wfs:FeatureCollection xmlns:testbed11="http://opengeospatial.org"
    xmlns:wfs="http://www.opengis.net/wfs" xmlns:gml="http://www.opengis.net/gml"
    xmlns:ogc="http://www.opengis.net/ogc" xmlns:ows="http://www.opengis.net/ows"
    xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:wml2="http://www.opengis.net/waterml/2.0" xmlns:sf="http://www.opengis.net/sampling/2.0"
    xmlns:sams="http://www.opengis.net/samplingSpatial/2.0"
    numberOfFeatures="1" timeStamp="2016-02-15T16:24:55.640Z"
    xsi:schemaLocation="http://www.opengis.net/wfs http://geoprocessing.demo.52north.org:8080/geoserver/schemas/wfs/1.1.0/wfs.xsd">
    <gml:featureMembers>
       <wml2:MonitoringPoint gml:id="xyz.1">
          <gml:identifier codeSpace="http://www.opengis.net/def/nil/OGC/0/unknown">xyz</gml:identifier>
          <gml:name codeSpace="http://www.opengis.net/def/nil/OGC/0/unknown">xyz</gml:name>
          <sf:sampledFeature xlink:href="urn:ogc:def:nil:OGC:unknown" />
          <sams:shape>
             <ns:Point xmlns:ns="http://www.opengis.net/gml/3.2"
                ns:id="point_xyz">
                <ns:pos srsName="http://www.opengis.net/def/crs/EPSG/0/31466">5668202.8356 2595842.8958</ns:pos>
             </ns:Point>
          </sams:shape>
       </wml2:MonitoringPoint>
    </gml:featureMembers>
       </wfs:FeatureCollection>"
        },
        "_id": "target-variable-point"
    }
      ],
      "output": {
    "_mimeType": "application/om+xml; version=2.0",
    "_schema": "http://schemas.opengis.net/om/2.0/observation.xsd",
    "_id": "estimated-values",
    "_transmission": "value"
      }, 
      "_service": "WPS",
      "_version": "2.0.0"}
    }
     */

    jsonGenerator.writeStartObject();

    jsonGenerator.writeObjectFieldStart("Execute");

    jsonGenerator.writeStringField("Identifier", executeBody_short.getProcessId());

    jsonGenerator.writeArrayFieldStart("Input");

    List<ExecuteInput> inputs = executeBody_short.getInputs();

    for (ExecuteInput executeInput : inputs) {
        jsonGenerator.writeObject(executeInput);
    }

    jsonGenerator.writeEndArray();

    /**
     * TODO is it really correct, that "output" starts with a small "o"?
     */
    jsonGenerator.writeArrayFieldStart("output");

    List<ExecuteOutput> outputs = executeBody_short.getOutputs();

    for (ExecuteOutput executeOutput : outputs) {
        jsonGenerator.writeObject(executeOutput);
    }

    jsonGenerator.writeEndArray();

    jsonGenerator.writeStringField("_service", Execute_HttpPostBody.service);

    jsonGenerator.writeStringField("_version", executeBody_short.getVersion());

    jsonGenerator.writeEndObject();

    jsonGenerator.writeEndObject();

    logger.info("Serialization of execute HTTP POST input body ended.");
}

From source file:de.escalon.hypermedia.spring.hydra.LinkListSerializer.java

@Override
public void serialize(List<Link> links, JsonGenerator jgen, SerializerProvider serializerProvider)
        throws IOException {

    try {//from   ww w  .  ja va  2s  .  co m
        Collection<Link> simpleLinks = new ArrayList<Link>();
        Collection<Affordance> affordances = new ArrayList<Affordance>();
        Collection<Link> templatedLinks = new ArrayList<Link>();
        Collection<Affordance> collectionAffordances = new ArrayList<Affordance>();
        Link selfRel = null;
        for (Link link : links) {
            if (link instanceof Affordance) {
                final Affordance affordance = (Affordance) link;
                final List<ActionDescriptor> actionDescriptors = affordance.getActionDescriptors();
                if (!actionDescriptors.isEmpty()) {
                    // TODO: consider to use Link href for template even if it is not compatible
                    if (affordance.getUriTemplateComponents().hasVariables()) {
                        // TODO resolve rel against context
                        if ("hydra:search".equals(affordance.getRel())
                                || Cardinality.SINGLE == affordance.getCardinality()) {
                            templatedLinks.add(affordance);
                        } else {
                            collectionAffordances.add(affordance);
                        }
                    } else {
                        // if all required variables are satisfied, the url can be used as identifier
                        // by stripping optional variables
                        if (!affordance.isSelfRel() && Cardinality.COLLECTION == affordance.getCardinality()) {
                            collectionAffordances.add(affordance);
                        } else {
                            affordances.add(affordance);
                        }
                    }
                } else {
                    if (affordance.isTemplated()) {
                        templatedLinks.add(affordance);
                    } else {
                        simpleLinks.add(affordance);
                    }
                }
            } else if (link.isTemplated()) {
                templatedLinks.add(link);
            } else {
                simpleLinks.add(link);
            }
            if ("self".equals(link.getRel())) {
                selfRel = link;
            }
        }

        for (Link templatedLink : templatedLinks) {
            // templated affordance might turn out to have all variables satisfied or
            // only optional unsatisfied variables
            ActionDescriptor actionDescriptorForHttpGet = getActionDescriptorForHttpGet(templatedLink);
            // TODO handle rev here
            String rel = templatedLink.getRel();
            writeIriTemplate(rel, templatedLink.getHref(), templatedLink.getVariableNames(),
                    actionDescriptorForHttpGet, jgen);
        }
        @SuppressWarnings("unchecked")
        Deque<LdContext> contextStack = (Deque<LdContext>) serializerProvider
                .getAttribute(JacksonHydraSerializer.KEY_LD_CONTEXT);
        String currentVocab = (contextStack != null && !contextStack.isEmpty()) ? contextStack.peek().vocab
                : null;

        // related collections
        if (!collectionAffordances.isEmpty()) {

            jgen.writeArrayFieldStart("hydra:collection");

            for (Affordance collectionAffordance : collectionAffordances) {
                jgen.writeStartObject();
                jgen.writeStringField(JsonLdKeywords.AT_TYPE, "hydra:Collection");
                PartialUriTemplateComponents templateComponents = collectionAffordance
                        .getUriTemplateComponents();
                if (!collectionAffordance.isBaseUriTemplated()
                        && !collectionAffordance.hasUnsatisfiedRequiredVariables()) {
                    String collectionUri = templateComponents.getBaseUri() + templateComponents.getQueryHead();
                    jgen.writeStringField(JsonLdKeywords.AT_ID, collectionUri);
                }
                if (templateComponents.hasVariables()) {
                    ActionDescriptor actionDescriptorForHttpGet = getActionDescriptorForHttpGet(
                            collectionAffordance);
                    writeIriTemplate("hydra:search", templateComponents.toString(),
                            templateComponents.getVariableNames(), actionDescriptorForHttpGet, jgen);
                }
                jgen.writeObjectFieldStart("hydra:manages");
                // do we have a collection holder which is not owner of the affordance?
                TypedResource collectionHolder = collectionAffordance.getCollectionHolder();
                if (collectionAffordance.getRev() != null) {
                    jgen.writeStringField("hydra:property", collectionAffordance.getRev());
                    if (collectionHolder != null) {
                        // can't use writeObjectField, it won't inherit the context stack
                        writeCollectionHolder("hydra:object", collectionHolder, jgen);
                    } else if (selfRel != null) {
                        jgen.writeStringField("hydra:object", selfRel.getHref());
                    }
                } else if (collectionAffordance.getRel() != null) {
                    jgen.writeStringField("hydra:property", collectionAffordance.getRel());
                    if (collectionHolder != null) {
                        // can't use writeObjectField, it won't inherit the context stack
                        writeCollectionHolder("hydra:subject", collectionHolder, jgen);
                    } else if (selfRel != null) {
                        jgen.writeStringField("hydra:subject", selfRel.getHref());
                    }
                }
                jgen.writeEndObject(); // end manages

                List<ActionDescriptor> actionDescriptors = collectionAffordance.getActionDescriptors();
                if (!actionDescriptors.isEmpty()) {
                    jgen.writeArrayFieldStart("hydra:operation");
                }
                writeActionDescriptors(jgen, currentVocab, actionDescriptors);
                if (!actionDescriptors.isEmpty()) {
                    jgen.writeEndArray(); // end hydra:operation
                }

                jgen.writeEndObject(); // end collection
            }
            jgen.writeEndArray();
        }

        for (Affordance affordance : affordances) {
            final String rel = affordance.getRel();
            List<ActionDescriptor> actionDescriptors = affordance.getActionDescriptors();

            if (!actionDescriptors.isEmpty()) {
                if (!Link.REL_SELF.equals(rel)) {
                    jgen.writeObjectFieldStart(rel); // begin rel
                }
                jgen.writeStringField(JsonLdKeywords.AT_ID, affordance.getHref());
                jgen.writeArrayFieldStart("hydra:operation");
            }

            writeActionDescriptors(jgen, currentVocab, actionDescriptors);

            if (!actionDescriptors.isEmpty()) {
                jgen.writeEndArray(); // end hydra:operation

                if (!Link.REL_SELF.equals(rel)) {
                    jgen.writeEndObject(); // end rel
                }
            }
        }

        for (Link simpleLink : simpleLinks) {
            final String rel = simpleLink.getRel();
            if (Link.REL_SELF.equals(rel)) {
                jgen.writeStringField("@id", simpleLink.getHref());
            } else {
                String linkAttributeName = IanaRels.isIanaRel(rel) ? IANA_REL_PREFIX + rel : rel;
                jgen.writeObjectFieldStart(linkAttributeName);
                jgen.writeStringField("@id", simpleLink.getHref());
                jgen.writeEndObject();
            }
        }
    } catch (IntrospectionException e) {
        throw new RuntimeException(e);
    }
}

From source file:de.escalon.hypermedia.spring.hydra.LinkListSerializer.java

/**
 * Writes bean description recursively.//w ww .  j  a  v  a  2  s . com
 *
 * @param jgen
 *         to write to
 * @param currentVocab
 *         in context
 * @param valueType
 *         class of value
 * @param allRootParameters
 *         of the method that receives the request body
 * @param rootParameter
 *         the request body
 * @param currentCallValue
 *         the value at the current recursion level
 * @param propertyPath
 *         of the current recursion level
 * @throws IntrospectionException
 * @throws IOException
 */
private void recurseSupportedProperties(JsonGenerator jgen, String currentVocab, Class<?> valueType,
        ActionDescriptor allRootParameters, ActionInputParameter rootParameter, Object currentCallValue,
        String propertyPath) throws IntrospectionException, IOException {

    Map<String, ActionInputParameter> properties = new HashMap<String, ActionInputParameter>();

    // collect supported properties from ctor

    Constructor[] constructors = valueType.getConstructors();
    // find default ctor
    Constructor constructor = PropertyUtils.findDefaultCtor(constructors);
    // find ctor with JsonCreator ann
    if (constructor == null) {
        constructor = PropertyUtils.findJsonCreator(constructors, JsonCreator.class);
    }
    if (constructor == null) {
        // TODO this can be a generic collection, find a way to describe it
        LOG.warn("can't describe supported properties, no default constructor or JsonCreator found for type "
                + valueType.getName());
        return;
    }

    int parameterCount = constructor.getParameterTypes().length;
    if (parameterCount > 0) {
        Annotation[][] annotationsOnParameters = constructor.getParameterAnnotations();

        Class[] parameters = constructor.getParameterTypes();
        int paramIndex = 0;
        for (Annotation[] annotationsOnParameter : annotationsOnParameters) {
            for (Annotation annotation : annotationsOnParameter) {
                if (JsonProperty.class == annotation.annotationType()) {
                    JsonProperty jsonProperty = (JsonProperty) annotation;
                    // TODO use required attribute of JsonProperty
                    String paramName = jsonProperty.value();

                    Object propertyValue = PropertyUtils.getPropertyOrFieldValue(currentCallValue, paramName);

                    ActionInputParameter constructorParamInputParameter = new SpringActionInputParameter(
                            new MethodParameter(constructor, paramIndex), propertyValue);

                    // TODO collect ctor params, setter params and process
                    // TODO then handle single, collection and bean for both
                    properties.put(paramName, constructorParamInputParameter);
                    paramIndex++; // increase for each @JsonProperty
                }
            }
        }
        Assert.isTrue(parameters.length == paramIndex, "not all constructor arguments of @JsonCreator "
                + constructor.getName() + " are annotated with @JsonProperty");
    }

    // collect supported properties from setters

    // TODO support Option provider by other method args?
    final BeanInfo beanInfo = Introspector.getBeanInfo(valueType);
    final PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
    // TODO collection and map
    // TODO distinguish which properties should be printed as supported - now just setters
    for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
        final Method writeMethod = propertyDescriptor.getWriteMethod();
        if (writeMethod == null) {
            continue;
        }
        // TODO: the property name must be a valid URI - need to check context for terms?
        String propertyName = getWritableExposedPropertyOrPropertyName(propertyDescriptor);

        Object propertyValue = PropertyUtils.getPropertyOrFieldValue(currentCallValue,
                propertyDescriptor.getName());

        MethodParameter methodParameter = new MethodParameter(propertyDescriptor.getWriteMethod(), 0);
        ActionInputParameter propertySetterInputParameter = new SpringActionInputParameter(methodParameter,
                propertyValue);

        properties.put(propertyName, propertySetterInputParameter);
    }

    // write all supported properties
    // TODO we are using the annotatedParameter.parameterName but should use the key of properties here:
    for (ActionInputParameter annotatedParameter : properties.values()) {
        String nextPropertyPathLevel = propertyPath.isEmpty() ? annotatedParameter.getParameterName()
                : propertyPath + '.' + annotatedParameter.getParameterName();
        if (DataType.isSingleValueType(annotatedParameter.getParameterType())) {

            final Object[] possiblePropertyValues = rootParameter.getPossibleValues(allRootParameters);

            if (rootParameter.isIncluded(nextPropertyPathLevel)
                    && !rootParameter.isExcluded(nextPropertyPathLevel)) {
                writeSupportedProperty(jgen, currentVocab, annotatedParameter,
                        annotatedParameter.getParameterName(), possiblePropertyValues);
            }
            // TODO collections?
            //                        } else if (DataType.isArrayOrCollection(parameterType)) {
            //                            Object[] callValues = rootParameter.getValues();
            //                            int items = callValues.length;
            //                            for (int i = 0; i < items; i++) {
            //                                Object value;
            //                                if (i < callValues.length) {
            //                                    value = callValues[i];
            //                                } else {
            //                                    value = null;
            //                                }
            //                                recurseSupportedProperties(jgen, currentVocab, rootParameter
            // .getParameterType(),
            //                                        allRootParameters, rootParameter, value);
            //                            }
        } else {
            jgen.writeStartObject();
            jgen.writeStringField("hydra:property", annotatedParameter.getParameterName());
            // TODO: is the property required -> for bean props we need the Access annotation to express that
            jgen.writeObjectFieldStart(getPropertyOrClassNameInVocab(currentVocab, "rangeIncludes",
                    LdContextFactory.HTTP_SCHEMA_ORG, "schema:"));
            Expose expose = AnnotationUtils.getAnnotation(annotatedParameter.getParameterType(), Expose.class);
            String subClass;
            if (expose != null) {
                subClass = expose.value();
            } else {
                subClass = annotatedParameter.getParameterType().getSimpleName();
            }
            jgen.writeStringField(getPropertyOrClassNameInVocab(currentVocab, "subClassOf",
                    "http://www.w3" + ".org/2000/01/rdf-schema#", "rdfs:"), subClass);

            jgen.writeArrayFieldStart("hydra:supportedProperty");

            Object propertyValue = PropertyUtils.getPropertyOrFieldValue(currentCallValue,
                    annotatedParameter.getParameterName());

            recurseSupportedProperties(jgen, currentVocab, annotatedParameter.getParameterType(),
                    allRootParameters, rootParameter, propertyValue, nextPropertyPathLevel);
            jgen.writeEndArray();

            jgen.writeEndObject();
            jgen.writeEndObject();
        }
    }
}