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.internal;
018
019import java.util.*;
020import java.util.concurrent.*;
021import java.util.function.*;
022
023import org.apache.juneau.*;
024import org.apache.juneau.collections.*;
025import org.apache.juneau.common.utils.*;
026import org.apache.juneau.reflect.*;
027
028/**
029 * Various generic object utility methods.
030 *
031 * <h5 class='section'>See Also:</h5><ul>
032 * </ul>
033 */
034public class Utils2 extends Utils {
035
036   /**
037    * If the specified object is a {@link Supplier} or {@link Value}, returns the inner value, otherwise the same value.
038    *
039    * @param o The object to unwrap.
040    * @return The unwrapped object.
041    */
042   public static Object unwrap(Object o) {
043      if (o instanceof Supplier)
044         o = unwrap(((Supplier<?>)o).get());
045      if (o instanceof Value)
046         o = unwrap(((Value<?>)o).get());
047      if (o instanceof Optional)
048         o = unwrap(((Optional<?>)o).orElse(null));
049      return o;
050   }
051
052   /**
053    * Converts the specified object into an identifiable string of the form "Class[identityHashCode]"
054    * @param o The object to convert to a string.
055    * @return An identity string.
056    */
057   public static String identity(Object o) {
058      if (o instanceof Optional)
059         o = ((Optional<?>)o).orElse(null);
060      if (o == null)
061         return null;
062      return ClassInfo.of(o).getShortName() + "@" + System.identityHashCode(o);
063   }
064
065   private static final ConcurrentHashMap<Class<?>,Map<String,MethodInfo>> PROPERTIES_METHODS = new ConcurrentHashMap<>();
066
067   /**
068    * Searches for all <c>properties()</c> methods on the specified object and creates a combine map of them.
069    *
070    * @param o The object to return a property map of.
071    * @return A new property map.
072    */
073   public static JsonMap toPropertyMap(Object o) {
074      if (o == null)
075         return null;
076      Map<String,MethodInfo> methods = PROPERTIES_METHODS.get(o.getClass());
077      if (methods == null) {
078         ClassInfo ci = ClassInfo.of(o);
079         Map<String,MethodInfo> methods2 = new LinkedHashMap<>();
080         do {
081            String cname = ci.getShortName();
082            MethodInfo mi = ci.getDeclaredMethod(x -> x.hasName("properties"));
083            if (mi != null)
084               methods2.put(cname, mi.accessible());
085            ci = ci.getSuperclass();
086         } while (ci != null);
087         methods = methods2;
088         PROPERTIES_METHODS.put(o.getClass(), methods);
089      }
090      JsonMap m = JsonMap.create().append("id", identity(o));
091      methods.forEach((k,v) -> m.put(k, v.invoke(o)));
092      return m;
093   }
094}