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.objecttools;
018
019import java.lang.reflect.*;
020import java.util.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.common.utils.*;
024import org.apache.juneau.internal.*;
025
026/**
027 * POJO model viewer.
028 *
029 * <p>
030 *    This class is designed to extract properties from collections of maps or beans.
031 * </p>
032 *
033 * <h5 class='section'>Example:</h5>
034 * <p class='bjava'>
035 *    MyBean[] <jv>arrayOfBeans</jv> = ...;
036 *    ObjectViewer <jv>viewer</jv> = ObjectViewer.<jsm>create</jsm>();
037 *
038 *    <jc>// Returns the 'foo' and 'bar' properties extracted into a list of maps.</jc>
039 *    List&lt;Map&gt; <jv>result</jv> = <jv>viewer</jv>.run(<jv>arrayOfBeans</jv>, <js>"foo,bar"</js>);
040 * </p>
041 * <p>
042 *    The tool can be used against the following data types:
043 * </p>
044 * <ul>
045 *    <li>Arrays/collections of maps or beans.
046 *    <li>Singular maps or beans.
047 * </ul>
048 *
049 * <h5 class='section'>See Also:</h5><ul>
050 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/ObjectTools">Object Tools</a>
051
052 * </ul>
053 */
054@SuppressWarnings({"unchecked","rawtypes"})
055public class ObjectViewer implements ObjectTool<ViewArgs> {
056
057   //-----------------------------------------------------------------------------------------------------------------
058   // Static
059   //-----------------------------------------------------------------------------------------------------------------
060
061   /**
062    * Default reusable searcher.
063    */
064   public static final ObjectViewer DEFAULT = new ObjectViewer();
065
066   /**
067    * Static creator.
068    *
069    * @return A new {@link ObjectViewer} object.
070    */
071   public static ObjectViewer create() {
072      return new ObjectViewer();
073   }
074
075   //-----------------------------------------------------------------------------------------------------------------
076   // Instance
077   //-----------------------------------------------------------------------------------------------------------------
078
079   /**
080    * Runs this viewer on the specified collection or array of objects.
081    *
082    * @param input The input.  Must be an array or collection.
083    * @param args The view args.  See {@link ViewArgs} for format.
084    * @return The extracted properties from the collection of objects.
085    */
086   public List<Map> run(Object input, String args) {
087      return (List<Map>)run(BeanContext.DEFAULT_SESSION, input, ViewArgs.create(args));
088   }
089
090   /**
091    * Runs this viewer on a singleton object.
092    *
093    * @param input The input.  Must be a singleton object.
094    * @param args The view args.  See {@link ViewArgs} for format.
095    * @return The extracted properties from the object.
096    */
097   public Map runSingle(Object input, String args) {
098      return (Map)run(BeanContext.DEFAULT_SESSION, input, ViewArgs.create(args));
099   }
100
101   @Override /* ObjectTool */
102   public Object run(BeanSession session, Object input, ViewArgs args) {
103
104      if (input == null)
105         return null;
106
107      List<String> view = args.getView();
108      ClassMeta type = session.getClassMetaForObject(input);
109
110      if (type.isBeanMap())
111         return new DelegateBeanMap(((BeanMap)input).getBean(), session).filterKeys(view);
112      if (type.isMap())
113         return new DelegateMap((Map)input, session).filterKeys(view);
114      if (type.isBean())
115         return new DelegateBeanMap(input, session).filterKeys(view);
116
117      ArrayList<Object> l = null;
118
119      if (type.isArray()) {
120         int size = Array.getLength(input);
121         l = Utils.listOfSize(size);
122         for (int i = 0; i < size; i++)
123            l.add(Array.get(input, i));
124      } else if (type.isCollection()) {
125         Collection c = (Collection)input;
126         l = Utils.listOfSize(c.size());
127         List<Object> l2 = l;
128         c.forEach(x -> l2.add(x));
129      } else {
130         return input;
131      }
132
133      for (ListIterator li = l.listIterator(); li.hasNext();) {
134         Object o = li.next();
135         ClassMeta cm2 = session.getClassMetaForObject(o);
136
137         if (cm2 == null)
138            o = null;
139         else if (cm2.isBeanMap())
140            o = new DelegateBeanMap(((BeanMap)o).getBean(), session).filterKeys(view);
141         else if (cm2.isMap())
142            o = new DelegateMap((Map)o, session).filterKeys(view);
143         else if (cm2.isBean())
144            o = new DelegateBeanMap(o, session).filterKeys(view);
145
146         li.set(o);
147      }
148
149      return l;
150   }
151}