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.bean.hal;
018
019import java.util.*;
020
021import org.apache.juneau.marshall.*;
022import org.apache.juneau.marshall.parser.*;
023import org.apache.juneau.marshall.serializer.*;
024import org.apache.juneau.marshall.swap.spi.*;
025
026/**
027 * Per-property {@link ObjectSwap} applied to HAL {@code _embedded} maps so that each map entry round-trips
028 * as either a single {@link HalResource} (JSON object) or a {@link HalResourceArray} (JSON array) per the
029 * spec.
030 *
031 * <p>
032 * The swap operates on the whole {@code Map<String,Object>} bean property and walks the entries:
033 * <ul class='spaced-list'>
034 *   <li>On <b>serialize</b> ({@link #swap}): identity - values that are {@link HalResource} or
035 *     {@link HalResourceArray} already serialize as the correct JSON shape.
036 *   <li>On <b>parse</b> ({@link #unswap}): each value that came back as a parsed list is converted to
037 *     {@link HalResourceArray}; each value that came back as a parsed map is converted to {@link HalResource}.
038 *   <li>{@code null} input ⇒ {@code null} output.
039 * </ul>
040 */
041public class HalResourceOrArraySwap extends ObjectSwap<Object,Object> {
042
043   @Override /* Overridden from ObjectSwap */
044   public Object swap(MarshallingSession session, Object o) throws SerializeException {
045      return o;
046   }
047
048   @Override /* Overridden from ObjectSwap */
049   public Object unswap(MarshallingSession session, Object o, ClassMeta<?> hint) throws ParseException {
050      if (o == null)
051         return null;
052      if (o instanceof Map<?,?> raw) {
053         var out = new LinkedHashMap<String,Object>();
054         var resCm = session.getClassMeta(HalResource.class);
055         var arrCm = session.getClassMeta(HalResourceArray.class);
056         for (var e : raw.entrySet()) {
057            var key = String.valueOf(e.getKey());
058            var v = e.getValue();
059            if (v instanceof Collection<?>) {
060               out.put(key, session.convertToType(v, arrCm));
061            } else if (v instanceof Map<?,?>) {
062               out.put(key, session.convertToType(v, resCm));
063            } else {
064               out.put(key, v);
065            }
066         }
067         return out;
068      }
069      return o;
070   }
071}