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

org.apache.bval.jsr303.resolver.CachingTraversableResolver Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
/*
 * 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.bval.jsr303.resolver;

import javax.validation.Path;
import javax.validation.TraversableResolver;
import java.lang.annotation.ElementType;
import java.util.HashMap;
import java.util.Map;

/**
 * Cache results of a delegated traversable resovler to optimize calls
 * It works only for a single validate* call and should not be used if
 * the TraversableResolver is accessed concurrently
 * 

* Date: 25.11.2009
* Time: 13:56:18
* * @author Roman Stumm (based on the code of Emmanuel Bernard) */ public class CachingTraversableResolver implements TraversableResolver, CachingRelevant { private TraversableResolver delegate; private Map cache = new HashMap(); /** * Convenience method to check whether caching is necessary on a given {@link TraversableResolver}. * @param resolver to check * @return true when a CachingTraversableResolver is to be used during validation */ public static boolean needsCaching(TraversableResolver resolver) { // caching, if we do not know exactly return !(resolver instanceof CachingRelevant) || ((CachingRelevant) resolver).needsCaching(); } /** * Create a new CachingTraversableResolver instance. * @param delegate */ public CachingTraversableResolver(TraversableResolver delegate) { this.delegate = delegate; } /** * If necessary, return a caching wrapper for the specified {@link TraversableResolver}. * @param traversableResolver * @return {@link TraversableResolver} * @see #needsCaching(TraversableResolver) */ public static TraversableResolver cacheFor(TraversableResolver traversableResolver) { if (needsCaching(traversableResolver)) { return new CachingTraversableResolver(traversableResolver); } else { return traversableResolver; } } /** * {@inheritDoc} */ public boolean isReachable(Object traversableObject, Path.Node traversableProperty, Class rootBeanType, Path pathToTraversableObject, ElementType elementType) { CacheEntry currentLH = new CacheEntry(traversableObject, traversableProperty, rootBeanType, pathToTraversableObject, elementType); CacheEntry cachedLH = cache.get(currentLH); if (cachedLH == null) { currentLH.reachable = delegate.isReachable(traversableObject, traversableProperty, rootBeanType, pathToTraversableObject, elementType); cache.put(currentLH, currentLH); cachedLH = currentLH; } else if (cachedLH.reachable == null) { cachedLH.reachable = delegate.isReachable(traversableObject, traversableProperty, rootBeanType, pathToTraversableObject, elementType); } return cachedLH.reachable; } /** * {@inheritDoc} */ public boolean isCascadable(Object traversableObject, Path.Node traversableProperty, Class rootBeanType, Path pathToTraversableObject, ElementType elementType) { CacheEntry currentLH = new CacheEntry(traversableObject, traversableProperty, rootBeanType, pathToTraversableObject, elementType); CacheEntry cachedLH = cache.get(currentLH); if (cachedLH == null) { currentLH.cascadable = delegate.isCascadable(traversableObject, traversableProperty, rootBeanType, pathToTraversableObject, elementType); cache.put(currentLH, currentLH); cachedLH = currentLH; } else if (cachedLH.cascadable == null) { cachedLH.cascadable = delegate.isCascadable(traversableObject, traversableProperty, rootBeanType, pathToTraversableObject, elementType); } return cachedLH.cascadable; } /** * {@inheritDoc} */ public boolean needsCaching() { return false; // I am the cache. Do not need cache for cache } /** * Entry in the cache. */ private static class CacheEntry { private final Object object; private final Path.Node node; private final Class type; private final Path path; private final ElementType elementType; private final int hashCode; private Boolean reachable; private Boolean cascadable; /** * Create a new CacheEntry instance. * @param traversableObject * @param traversableProperty * @param rootBeanType * @param pathToTraversableObject * @param elementType */ private CacheEntry(Object traversableObject, Path.Node traversableProperty, Class rootBeanType, Path pathToTraversableObject, ElementType elementType) { this.object = traversableObject; this.node = traversableProperty; this.type = rootBeanType; this.path = pathToTraversableObject; this.elementType = elementType; this.hashCode = buildHashCode(); } /** * {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } CacheEntry that = (CacheEntry) o; return elementType == that.elementType && path.equals(that.path) && type.equals(that.type) && !(object != null ? !object.equals(that.object) : that.object != null) && node.equals(that.node); } /** * {@inheritDoc} */ @Override public int hashCode() { return hashCode; } private int buildHashCode() { int result = object != null ? object.hashCode() : 0; result = 31 * result + node.hashCode(); result = 31 * result + type.hashCode(); result = 31 * result + path.hashCode(); result = 31 * result + elementType.hashCode(); return result; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy