001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.marshall.serializer; 018 019 020import java.io.*; 021 022import org.apache.juneau.marshall.*; 023import static org.apache.juneau.commons.utils.Shorts.*; 024 025/** 026 * Subclass of {@link SerializerSession} for stream-based serializers. 027 * 028 * <h5 class='topic'>Description</h5> 029 * 030 * This class is the parent class of all byte-based serializers. 031 * <br>It has 1 abstract method to implement... 032 * <ul> 033 * <li>{@link #doWrite(SerializerPipe, Object)} 034 * </ul> 035 * 036 * <h5 class='section'>Notes:</h5><ul> 037 * <li class='warn'>This class is not thread safe and is typically discarded after one use. 038 * </ul> 039 * 040 * <h5 class='section'>See Also:</h5><ul> 041 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SerializersAndParsers">Serializers and Parsers</a> 042 * </ul> 043 */ 044@SuppressWarnings({ 045 "java:S110", // Deep inheritance inherent to the serializer/parser session hierarchy 046 "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants 047 "resource" // Internal helpers return Closeables wired into pipe lifecycle; Eclipse JDT @Owning warning is by design. 048}) 049public class OutputStreamSerializerSession extends SerializerSession { 050 051 /** 052 * Builder class. 053 */ 054 @SuppressWarnings({ 055 "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name. 056 }) 057 public abstract static class Builder<SELF extends Builder<SELF>> extends SerializerSession.Builder<SELF> { 058 059 private final OutputStreamSerializer ctx; 060 061 /** 062 * Constructor 063 * 064 * @param ctx The context creating this session. 065 * <br>Cannot be <jk>null</jk>. 066 */ 067 protected Builder(OutputStreamSerializer ctx) { 068 super(reqnn("ctx", ctx)); 069 this.ctx = ctx; 070 } 071 072 @Override 073 public OutputStreamSerializerSession build() { 074 return new OutputStreamSerializerSession(this); 075 } 076 077 } 078 079 /** 080 * Concrete default builder leaf for the non-subclassed {@code create()} path (CRTP terminal). 081 */ 082 public static final class DefaultBuilder extends Builder<DefaultBuilder> { 083 084 DefaultBuilder(OutputStreamSerializer ctx) { 085 super(ctx); 086 } 087 } 088 089 /** 090 * Creates a new builder for this object. 091 * 092 * @param ctx The context creating this session. 093 * <br>Cannot be <jk>null</jk>. 094 * @return A new builder. 095 */ 096 @SuppressWarnings({ 097 "java:S1452" // Builder<?> wildcard return intentional; callers use it to construct session instances polymorphically 098 }) 099 public static Builder<?> create(OutputStreamSerializer ctx) { 100 return new DefaultBuilder(reqnn("ctx", ctx)); 101 } 102 103 private final OutputStreamSerializer ctx; 104 105 /** 106 * Constructor. 107 * 108 * @param builder The builder for this object. 109 * <br>Cannot be <jk>null</jk>. 110 */ 111 protected OutputStreamSerializerSession(Builder<?> builder) { 112 super(builder); 113 ctx = builder.ctx; 114 } 115 116 @Override /* Overridden from SerializerSession */ 117 public final boolean isWriterSerializer() { return false; } 118 119 /** 120 * Convenience method for serializing an object to a <code><jk>byte</jk></code>. 121 * 122 * @param o The object to serialize. 123 * @return The output serialized to a byte array. 124 * @throws SerializeException If a problem occurred trying to convert the output. 125 */ 126 @Override /* Overridden from SerializerSession */ 127 public final byte[] write(Object o) throws SerializeException { 128 var baos = new ByteArrayOutputStream(); 129 try { 130 write(o, baos); 131 baos.flush(); 132 } catch (IOException e) { 133 throw new SerializeException(e); // Should never happen. 134 } 135 return baos.toByteArray(); 136 } 137 138 @Override /* Overridden from SerializerSession */ 139 public final String writeToString(Object o) throws SerializeException { 140 // Stream-to-string is a debug / display convenience for binary serializer output (BSON / MsgPack / 141 // CBOR / Prototext / Parquet). It always emits HEX irrespective of the configured BinaryFormat so that 142 // downstream tooling (test fixtures, log lines, REPL output) gets a stable, copy-pasteable 143 // representation of the binary frame regardless of how the surrounding context configures byte[] 144 // cell encoding. 145 return BinaryFormat.HEX.format(write(o)); 146 } 147 148 @Override /* Overridden from SerializerSession */ 149 protected SerializerPipe createPipe(Object output) { 150 return new SerializerPipe(output); 151 } 152 153 /** 154 * Binary output format. 155 * 156 * @see MarshallingContext.Builder#binaryFormat(BinaryFormat) 157 * @return 158 * The format to use for the {@link #writeToString(Object)} method on stream-based serializers when converting byte arrays to strings. 159 */ 160 protected final BinaryFormat getBinaryFormat() { return ctx.getMarshallingContext().getBinaryFormat(); } 161 162 /** 163 * Returns whether this binary serializer has a native byte-array wire type. 164 * 165 * <p> 166 * When {@code true}, {@code byte[]} payloads bypass the configured 167 * {@link BinaryFormat} dispatch in {@link org.apache.juneau.marshall.swaps.BinarySwap} and the variant 168 * binary swap installed by {@code MarshalledPropertyPostProcessor}, and are written as raw 169 * bytes through the serializer's native binary opcode (e.g. MsgPack {@code bin} family, CBOR 170 * byte-string major type 2, BSON binary subtype {@code 0x05}). When {@code false}, the 171 * configured {@link BinaryFormat} fires for non-{@code NOT_SET} formats and produces a text 172 * wire form (HEX / BASE64 / etc.) that the serializer emits as a string in its native string 173 * column / literal type — used by serializers whose wire format has no native byte-array 174 * primitive (Parquet column writer, binary RDF formats). 175 * 176 * <p> 177 * Defaults to {@code true}. Subclasses without a native byte-array wire type 178 * (e.g. {@link org.apache.juneau.marshall.parquet.ParquetSerializerSession} and the binary RDF 179 * sessions) override and return {@code false}. 180 * 181 * @return {@code true} if this serializer has a native byte-array wire type. 182 */ 183 public boolean hasNativeBytes() { 184 return true; 185 } 186}