All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.juneau.swap.AutoListSwap Maven / Gradle / Ivy

// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
// * to you 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.apache.juneau.swap;

import static org.apache.juneau.internal.ClassUtils.*;
import static org.apache.juneau.internal.CollectionUtils.*;

import java.lang.reflect.*;
import java.util.*;

import org.apache.juneau.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.reflect.*;
import org.apache.juneau.serializer.*;

/**
 * A dynamic object swap based on reflection of a Java class that converts objects to Lists.
 *
 * 

* Looks for methods on the class that can be called to swap-in surrogate List objects before serialization and swap-out * surrogate List objects after parsing. * *

Valid surrogate objects
*
    *
  • Any subclass of {@link List} *
* *
Valid swap methods (S = Swapped type)
*
    *
  • public S toList() *
  • public S toList(BeanSession) *
  • public S toJsonList() *
  • public S toJsonList(BeanSession) *
* *
Valid unswap methods (N = Normal type, S = Swapped type)
*
    *
  • public static N fromList(S) *
  • public static N fromList(BeanSession, S) *
  • public static N fromJsonList(S) *
  • public static N fromJsonList(BeanSession, S) *
  • public static N create(S) *
  • public static N create(BeanSession, S) *
  • public static N valueOf(S) *
  • public static N valueOf(BeanSession, S) *
  • public N(S) *
* *

* Classes are ignored if any of the following are true: *

    *
  • Classes annotated with {@link BeanIgnore @BeanIgnore}. *
  • Non-static member classes. *
* *

* Members/constructors are ignored if any of the following are true: *

    *
  • Members/constructors annotated with {@link BeanIgnore @BeanIgnore}. *
  • Deprecated members/constructors. *
* *
See Also:
* * @param The normal class type. */ public class AutoListSwap extends ObjectSwap> { private static final Set SWAP_METHOD_NAMES = uset("toList", "toJsonList"), UNSWAP_METHOD_NAMES = uset("fromList", "fromJsonList", "create", "valueOf"); /** * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so. * * @param bc The bean context to use for looking up annotations. * @param ci The class to try to constructor a dynamic swap on. * @return An object swap instance, or null if one could not be created. */ @SuppressWarnings({ "rawtypes" }) public static ObjectSwap find(BeanContext bc, ClassInfo ci) { if (shouldIgnore(bc, ci)) return null; // Find swap() method if present. for (MethodInfo m : ci.getMethods()) { if (isSwapMethod(bc, m)) { ClassInfo rt = m.getReturnType(); MethodInfo mi = ci.getMethod(x -> isUnswapMethod(bc, x, ci, rt)); if (mi != null) return new AutoListSwap(bc, ci, m, mi, null); ConstructorInfo cs = ci.getDeclaredConstructor(x -> isUnswapConstructor(bc, x, rt)); if (cs != null) return new AutoListSwap(bc, ci, m, null, cs); return new AutoListSwap(bc, ci, m, null, null); } } return null; } private static boolean shouldIgnore(BeanContext bc, ClassInfo ci) { return ci.hasAnnotation(bc, BeanIgnore.class) || ci.isNonStaticMemberClass(); } private static boolean isSwapMethod(BeanContext bc, MethodInfo mi) { return mi.isNotDeprecated() && mi.isNotStatic() && mi.isVisible(bc.getBeanMethodVisibility()) && mi.hasName(SWAP_METHOD_NAMES) && mi.hasReturnTypeParent(List.class) && mi.hasFuzzyParamTypes(BeanSession.class) && mi.hasNoAnnotation(bc, BeanIgnore.class); } private static boolean isUnswapMethod(BeanContext bc, MethodInfo mi, ClassInfo ci, ClassInfo rt) { return mi.isNotDeprecated() && mi.isStatic() && mi.isVisible(bc.getBeanMethodVisibility()) && mi.hasName(UNSWAP_METHOD_NAMES) && mi.hasFuzzyParamTypes(BeanSession.class, rt.inner()) && mi.hasReturnTypeParent(ci) && mi.hasNoAnnotation(bc, BeanIgnore.class); } private static boolean isUnswapConstructor(BeanContext bc, ConstructorInfo cs, ClassInfo rt) { return cs.isNotDeprecated() && cs.isVisible(bc.getBeanConstructorVisibility()) && cs.hasMatchingParamTypes(rt) && cs.hasNoAnnotation(bc, BeanIgnore.class); } //------------------------------------------------------------------------------------------------------------------ private final Method swapMethod, unswapMethod; private final Constructor unswapConstructor; private AutoListSwap(BeanContext bc, ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) { super(ci.inner(), swapMethod.getReturnType().inner()); this.swapMethod = bc.getBeanMethodVisibility().transform(swapMethod.inner()); this.unswapMethod = unswapMethod == null ? null : bc.getBeanMethodVisibility().transform(unswapMethod.inner()); this.unswapConstructor = unswapConstructor == null ? null : bc.getBeanConstructorVisibility().transform(unswapConstructor.inner()); } @Override /* ObjectSwap */ public List swap(BeanSession session, Object o) throws SerializeException { try { return (List)swapMethod.invoke(o, getMatchingArgs(swapMethod.getParameterTypes(), session)); } catch (Exception e) { throw SerializeException.create(e); } } @SuppressWarnings("unchecked") @Override /* ObjectSwap */ public T unswap(BeanSession session, List o, ClassMeta hint) throws ParseException { try { if (unswapMethod != null) return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, o)); if (unswapConstructor != null) return (T)unswapConstructor.newInstance(o); return super.unswap(session, o, hint); } catch (Exception e) { throw ParseException.create(e); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy