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.swaps;
018
019import org.apache.juneau.marshall.*;
020import org.apache.juneau.marshall.csv.*;
021import org.apache.juneau.marshall.oapi.*;
022import org.apache.juneau.marshall.parser.*;
023import org.apache.juneau.marshall.serializer.*;
024import org.apache.juneau.marshall.swap.spi.*;
025
026/**
027 * Thin delegating swap for top-level {@code byte[]} values in textual serializers.
028 *
029 * <p>
030 * Used as a fall-back swap by {@link DefaultSwaps} for root-level / map-value /
031 * collection-element {@code byte[]} payloads that are not bean properties. Delegates to whichever
032 * {@link BinaryFormat} is configured on the
033 * {@link MarshallingContext}.
034 *
035 * <p>Disabled for:
036 * <ul>
037 *    <li>Binary serializers / parsers with a native byte-array wire type —
038 *       gated by {@link OutputStreamSerializerSession#hasNativeBytes()} /
039 *       {@link InputStreamParserSession#hasNativeBytes()}.  Sessions that return {@code true}
040 *       (MsgPack / CBOR / BSON) emit / consume native byte sequences and skip this swap.  Sessions
041 *       that return {@code false} (Parquet, binary RDF) have no native byte-array primitive and
042 *       still run this swap to produce / consume the configured text wire form.
043 *    <li>CSV serializers / parsers ({@link CsvSerializerSession} / {@link CsvParserSession}) — CSV exposes its
044 *       own per-cell {@code byteArrayFormat} setting via {@link CsvByteArrayCellFormat}.
045 *    <li>{@code null}-session lookups (i.e. {@link ClassMeta}-level conversion plumbing) — keeps the
046 *       String-to-{@code byte[]} fallback in {@code BasicConverter} / {@code MarshallingContext.findConversion}
047 *       on the simple {@link String#getBytes(java.nio.charset.Charset)} path for non-binary inputs.
048 * </ul>
049 *
050 * <h5 class='section'>See Also:</h5><ul>
051 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Swaps">Swap</a>
052 * </ul>
053 */
054public class BinarySwap extends StringSwap<byte[]> {
055
056   @Override /* Overridden from ObjectSwap */
057   public int match(MarshallingSession session) {
058      // Null sessions arrive from ClassMeta-level conversion lookup paths.  Returning 0 keeps the
059      // default String-to-byte[] conversion (UTF-8 getBytes) intact for callers that aren't actually
060      // trying to encode/decode a wire-format binary payload.
061      if (session == null)
062         return 0;
063      // Binary serializers / parsers with a native byte-array wire type handle byte[] natively — skip
064      // this swap so the underlying BSON / CBOR / MsgPack writer emits the raw byte sequence and the
065      // corresponding parser consumes it.  Binary serializers without a native byte-array wire type
066      // (Parquet, binary RDF) report hasNativeBytes()==false and still run this swap to produce /
067      // consume the configured text wire form (HEX / BASE64 / etc.).
068      if (session instanceof OutputStreamSerializerSession session2 && session2.hasNativeBytes())
069         return 0;
070      if (session instanceof InputStreamParserSession session2 && session2.hasNativeBytes())
071         return 0;
072      // CSV defers byte[] cell formatting to its own CsvByteArrayCellFormat-driven cell serializer/parser.
073      if (session instanceof CsvSerializerSession || session instanceof CsvParserSession)
074         return 0;
075      // OpenAPI part serializers/parsers drive byte[] cell encoding from the {@code format} schema attribute
076      // (BYTE / BINARY / BINARY_SPACED).  Skipping this swap leaves the raw byte[] in place so the
077      // OpenAPI session can apply the schema-directed encoding directly.
078      if (session instanceof OpenApiSerializerSession || session instanceof OpenApiParserSession)
079         return 0;
080      // NOT_SET means "no wire format configured" — leave byte[] in its native language form so the
081      // surrounding serializer falls back to its built-in array representation (e.g. JSON array).
082      if (session.getMarshallingContext().getBinaryFormat() == BinaryFormat.NOT_SET)
083         return 0;
084      return super.match(session);
085   }
086
087   @Override /* Overridden from ObjectSwap */
088   public String swap(MarshallingSession session, byte[] o) {
089      return session.getMarshallingContext().getBinaryFormat().format(o);
090   }
091
092   @Override /* Overridden from ObjectSwap */
093   public byte[] unswap(MarshallingSession session, String o, ClassMeta<?> hint) {
094      return session.getMarshallingContext().getBinaryFormat().parse(o);
095   }
096}