![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.juneau.objecttools.ObjectSearcher 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.objecttools;
import static org.apache.juneau.common.internal.StringUtils.*;
import static org.apache.juneau.internal.CollectionUtils.*;
import java.lang.reflect.*;
import java.util.*;
import org.apache.juneau.*;
/**
* POJO model searcher.
*
*
* This class is designed to provide searches across arrays and collections of maps or beans.
* It allows you to quickly filter beans and maps using simple yet sophisticated search arguments.
*
*
* Example:
*
* MyBean[] arrayOfBeans = ...;
* ObjectSearcher searcher = ObjectSearcher.create ();
*
* // Returns a list of beans whose 'foo' property is 'X' and 'bar' property is 'Y'.
* List<MyBean> result = searcher .run(arrayOfBeans , "foo=X,bar=Y" );
*
*
* The tool can be used against the following data types:
*
*
* - Arrays/collections of maps or beans.
*
*
* The default searcher is configured with the following matcher factories that provides the capabilities of matching
* against various data types. This list is extensible:
*
*
* - {@link StringMatcherFactory}
*
- {@link NumberMatcherFactory}
*
- {@link TimeMatcherFactory}
*
*
* The {@link StringMatcherFactory} class provides searching based on the following patterns:
*
*
* "property=foo" - Simple full word match
* "property=fo*" , "property=?ar" - Meta-character matching
* "property=foo bar" (implicit), "property=^foo ^bar" (explicit) - Multiple OR'ed patterns
* "property=+fo* +*ar" - Multiple AND'ed patterns
* "property=fo* -bar" - Negative patterns
* "property='foo bar'" - Patterns with whitespace
* "property=foo\\'bar" - Patterns with single-quotes
* "property=/foo\\s+bar" - Regular expression match
*
*
* The {@link NumberMatcherFactory} class provides searching based on the following patterns:
*
*
* "property=1" - A single number
* "property=1 2" - Multiple OR'ed numbers
* "property=-1 -2" - Multiple OR'ed negative numbers
* "property=1-2" ,"property=-2--1" - A range of numbers (whitespace ignored)
* "property=1-2 4-5" - Multiple OR'ed ranges
* "property=<1" ,"property=<=1" ,"property=>1" ,"property=>=1" - Open-ended ranges
* "property=!1" ,"property=!1-2" - Negation
*
*
* The {@link TimeMatcherFactory} class provides searching based on the following patterns:
*
*
* "property=2011" - A single year
* "property=2011 2013 2015" - Multiple years
* "property=2011-01" - A single month
* "property=2011-01-01" - A single day
* "property=2011-01-01T12" - A single hour
* "property=2011-01-01T12:30" - A single minute
* "property=2011-01-01T12:30:45" - A single second
* "property=>2011" ,"property=>=2011" ,"property=<2011" ,"property=<=2011" - Open-ended ranges
* "property=>2011" ,"property=>=2011" ,"property=<2011" ,"property=<=2011" - Open-ended ranges
* "property=2011 - 2013-06-30" - Closed ranges
*
*
* See Also:
*/
@SuppressWarnings({"rawtypes"})
public final class ObjectSearcher implements ObjectTool {
//-----------------------------------------------------------------------------------------------------------------
// Static
//-----------------------------------------------------------------------------------------------------------------
/**
* Default reusable searcher.
*/
public static final ObjectSearcher DEFAULT = new ObjectSearcher();
/**
* Static creator.
*
* @param factories
* The matcher factories to use.
*
If not specified, uses the following:
*
* - {@link StringMatcherFactory#DEFAULT}
*
- {@link NumberMatcherFactory#DEFAULT}
*
- {@link TimeMatcherFactory#DEFAULT}
*
* @return A new {@link ObjectSearcher} object.
*/
public static ObjectSearcher create(MatcherFactory...factories) {
return new ObjectSearcher(factories);
}
//-----------------------------------------------------------------------------------------------------------------
// Instance
//-----------------------------------------------------------------------------------------------------------------
final MatcherFactory[] factories;
/**
* Constructor.
*
* @param factories
* The matcher factories to use.
*
If not specified, uses the following:
*
* - {@link NumberMatcherFactory#DEFAULT}
*
- {@link TimeMatcherFactory#DEFAULT}
*
- {@link StringMatcherFactory#DEFAULT}
*
*/
public ObjectSearcher(MatcherFactory...factories) {
this.factories = factories.length == 0 ? new MatcherFactory[]{NumberMatcherFactory.DEFAULT, TimeMatcherFactory.DEFAULT, StringMatcherFactory.DEFAULT} : factories;
}
/**
* Convenience method for executing the searcher.
*
* @param The return type.
* @param input The input.
* @param searchArgs The search arguments. See {@link SearchArgs} for format.
* @return A list of maps/beans matching the
*/
@SuppressWarnings("unchecked")
public List run(Object input, String searchArgs) {
Object r = run(BeanContext.DEFAULT_SESSION, input, SearchArgs.create(searchArgs));
if (r instanceof List)
return (List)r;
if (r instanceof Collection)
return new ArrayList((Collection)r);
if (r.getClass().isArray())
return Arrays.asList((R[])r);
return null;
}
@Override /* ObjectTool */
public Object run(BeanSession session, Object input, SearchArgs args) {
ClassMeta> type = session.getClassMetaForObject(input);
Map search = args.getSearch();
if (search.isEmpty() || type == null || ! type.isCollectionOrArray())
return input;
List