ExpressionProviderFactory.java
/*******************************************************************************
* Copyright (c) 2018 @gt_tech
*
* Licensed 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.bitbucket.gt_tech.spring.data.querydsl.value.operators;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.DateTimePath;
import com.querydsl.core.types.dsl.EnumPath;
import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.core.types.dsl.StringPath;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.querydsl.binding.QuerydslBindings;
import org.springframework.data.querydsl.binding.QuerydslBindings.PathBinder;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* Main entry point for library consumers. Factory class provides access to
* appropriate {@link ExpressionProvider} based on provided {@link Path} type.
*
* @author gt_tech
*/
public final class ExpressionProviderFactory {
/*
Internal cache for ExpressionProvider objects
*/
static LoadingCache<Path, ExpressionProvider> loadingCache = CacheBuilder.newBuilder()
.build(new CacheLoader<Path, ExpressionProvider>() {
@Override
public ExpressionProvider load(Path key) throws Exception {
if (StringPath.class.isAssignableFrom(key.getClass())) {
return new StringPathExpressionProviderImpl();
} else if (EnumPath.class.isAssignableFrom(key.getClass())) {
return new EnumPathExpressionProviderImpl();
} else if (NumberPath.class.isAssignableFrom(key.getClass())) {
return new NumberPathExpressionProviderImpl();
} else if (DateTimePath.class.isAssignableFrom(key.getClass())) {
return new DateTimePathExpressionProviderImpl();
}
return null;
}
});
private static boolean supportsUnTypedValues = false;
/*
* Registry for storing path to alias mapping.
*/
private static Map<Path, String> path_alias_registry = new HashMap<>();
/**
* Returns an {@link Optional} of {@link ExpressionProvider} if available for the provided {@code Path} instance.
*
* @param path <code>Path</code> for which <code>ExpressionProvider</code> is to be returned.
* @return <code>Optional</code> containing <code>ExpressionProvider</code> if available or else an empty optional.
*/
public static Optional<ExpressionProvider> getProvider(Path path) {
return Optional.ofNullable(loadingCache.getUnchecked(path));
}
/**
* Create a predicate based on implementation specific logic's processing of
* supplied value(s).
*
* @param path <code>Path</code> path
* @param value Input value(s) (Must not be {@link Optional}, can be a primitive or collection
* @return {@link Optional} of {@link Predicate} based on provided value.
*/
public static Optional<Predicate> getPredicate(Path path, Object value) {
return Optional.ofNullable(loadingCache.getUnchecked(path))
.flatMap(p -> p.getPredicate(path, value));
}
/**
* Method registers the new alias for given Path. It is assumed that
* {@link PathBinder} available from {@link QuerydslBindings} is also
* updated with new alias prior to registering here.
*
* @param path {@link Path} on which alias is applied
* @param alias String alias value for supplied path
*/
public static void registerAlias(Path path, String alias) {
if (path != null && StringUtils.isNotBlank(alias)) {
path_alias_registry.put(path, alias);
}
}
/**
* @param path Path for which alias to be looked up from local registry.
* @return {@link Optional} of alias if available, otherwise empty
* {@link Optional}
*/
public static Optional<String> findAlias(Path path) {
return Optional.ofNullable(path)
.map(p -> path_alias_registry.get(p));
}
/**
* @return <code>true</code> when experimental features are turned on, implying that untyped
* values are going to be made available to {@link ExpressionProvider} for
* non-string paths, <code>false</code> is returned if experimental features are disabled
*/
public static boolean isSupportsUnTypedValues() {
return supportsUnTypedValues;
}
/**
* Sets whether experimental features are turned on, implying that untyped
* values are going to be made available to {@link ExpressionProvider} for
* non-string paths.
*
* @param supportsUnTypedValues <code>Boolean</code> indicating status of support of untyped values (aka. experimental features)
*/
public static void setSupportsUnTypedValues(boolean supportsUnTypedValues) {
ExpressionProviderFactory.supportsUnTypedValues = supportsUnTypedValues;
}
}