/*
* Copyright 2013, 2014 Deutsche Nationalbibliothek
*
* 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.culturegraph.mf.javaintegration.pojo;
import org.culturegraph.mf.framework.FluxCommand;
import org.culturegraph.mf.framework.StreamReceiver;
import org.culturegraph.mf.framework.annotations.Description;
import org.culturegraph.mf.framework.annotations.In;
import org.culturegraph.mf.framework.annotations.Out;
import org.culturegraph.mf.framework.helpers.DefaultObjectPipe;
/**
* Outputs a record by decoding the members of a given pojo (Plain Old Java
* Object). Each public getter or public field defines a member. The member name
* is either the getter name without the get prefix or the field name.
* <p>
* The generated stream events depend on the member type:
* <ul>
* <li>Simple types like Strings or the primitive types produces a literal
* event with the member name as literal name and the member value as literal
* value
*
* <li>Instances of {@link MetafactureSource} can insert user defined events
* into the stream by implementing the {@link MetafactureSource#sendToStream}
* method.
*
* <li>Complex types like other pojos produces an entity with the member name
* as entity name and the decoded pojo members as the entity's elements
*
* <li>Lists, Arrays and Sets produce events for each entry according to the
* rules above. Each of these events is named by the member name.
*
* <li>Maps produces an entity with the member name as entity name. Each map
* entry produces a sub entity with the string representation of the entry key
* as entity name and the entry value decoded to the rules above.
* </ul>
* <p>
* Here are some examples:
* <ul>
* <li>{@code String str = "abc" → literal("str", "abc")}
*
* <li>{@code boolean bo = true → literal("bo", "true")}
*
* <li>{@code List<String> li = … ("a", "b") → literal("li", "a"), literal("li", "b")}
*
* <li>{@code String[] ar = … ("a", "b") → literal("ar", "a"), literal("ar", "b")}
*
* <li>{@code Set<String> se = … ("a", "b") → literal("se", "a"), literal("se", "b")}
*
* <li>{@code Map<String, String> ma = … ("a" : "b", "c" : "d") → startEntity("ma"), literal("a", "b"), literal("c", "d"), endEntity()}
* </ul>
* <p>
* See in the test cases in {@code PojoDecoderTest} for more examples.
*
* @param <T>
* input object type
*
* @author Thomas Seidel
*
*/
@Description("Outputs a record containing the member values of the input pojo (Plain Old Java Object)")
@In(Object.class)
@Out(StreamReceiver.class)
@FluxCommand("decode-pojo")
public class PojoDecoder<T> extends DefaultObjectPipe<T, StreamReceiver> {
private final TypeDecoderFactory typeDecoderFactory = new TypeDecoderFactory();
@Override
public void process(final T obj) {
if (obj == null) {
return;
}
assert !isClosed();
final TypeDecoder typeDecoder = typeDecoderFactory.create(obj.getClass());
getReceiver().startRecord("");
typeDecoder.decodeToStream(getReceiver(), null, obj);
getReceiver().endRecord();
}
}