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

org.omnifaces.persistence.service.RootPathResolver Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021 OmniFaces
 *
 * 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
 *
 *     https://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.omnifaces.persistence.service;

import static java.lang.String.format;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Fetch;
import jakarta.persistence.criteria.FetchParent;
import jakarta.persistence.criteria.From;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Root;

/**
 * Helper class of {@link BaseEntityService}.
 */
class RootPathResolver implements PathResolver {

	private static final String ERROR_UNKNOWN_FIELD =
		"Field %s cannot be found on %s. If this represents a transient field, make sure that it is delegating to @ManyToOne/@OneToOne children.";

	private final Root root;
	private final Map> joins;
	private final Map> paths;
	private final Set elementCollections;
	private final Set manyOrOneToOnes;

	public RootPathResolver(Root root, Set elementCollections, Set manyOrOneToOnes) {
		this.root = root;
		this.joins = getJoins(root);
		this.paths = new HashMap<>();
		this.elementCollections = elementCollections;
		this.manyOrOneToOnes = manyOrOneToOnes;
	}

	@Override
	public Expression get(String field) {
		if (field == null) {
			return root;
		}

		Path path = paths.get(field);

		if (path != null) {
			return path;
		}

		path = root;
		boolean explicitJoin = field.charAt(0) == '@';
		String originalField = explicitJoin ? field.substring(1) : field;
		String[] attributes = originalField.split("\\.");
		int depth = attributes.length;

		for (int i = 0; i < depth; i++) {
			String attribute = attributes[i];

			if (i + 1 < depth || elementCollections.contains(originalField)) {
				path = explicitJoin || !joins.containsKey(attribute) ? ((From) path).join(attribute) : joins.get(attribute);
			}
			else {
				try {
					path = path.get(attribute);
				}
				catch (IllegalArgumentException e) {
					if (depth == 1 && isTransient(path.getModel().getBindableJavaType(), attribute)) {
						path = guessManyOrOneToOnePath(attribute);
					}

					if (depth != 1 || path == null) {
						throw new IllegalArgumentException(format(ERROR_UNKNOWN_FIELD, field, root.getJavaType()), e);
					}
				}
			}
		}

		paths.put(field, path);
		return path;
	}

	private boolean isTransient(Class type, String property) {
		return true; // TODO implement?
	}

	private Path guessManyOrOneToOnePath(String attribute) {
		for (String manyOrOneToOne : manyOrOneToOnes) {
			try {
				return (Path) get(manyOrOneToOne + "." + attribute);
			}
			catch (IllegalArgumentException ignore) {
				continue;
			}
		}

		return null;
	}

	private static Map> getJoins(From from) {
		Map> joins = new HashMap<>();
		collectJoins(from, joins);

		if (from instanceof EclipseLinkRoot) {
			((EclipseLinkRoot) from).collectPostponedFetches(joins);
		}

		return joins;
	}

	private static void collectJoins(Path path, Map> joins) {
		if (path instanceof From) {
			((From) path).getJoins().forEach(join -> collectJoins(join, joins));
		}
		if (path instanceof FetchParent) {
			try {
				((FetchParent) path).getFetches().stream().filter(fetch -> fetch instanceof Path).forEach(fetch -> collectJoins((Path) fetch, joins));
			}
			catch (NullPointerException openJPAWillThrowThisOnEmptyFetches) {
				// Ignore and continue.
			}
		}
		if (path instanceof Join) {
			joins.put(((Join) path).getAttribute().getName(), path);
		}
		else if (path instanceof Fetch) {
			joins.put(((Fetch) path).getAttribute().getName(), path);
		}
	}

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy