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

spoon.reflect.meta.impl.RoleHandlerHelper Maven / Gradle / Ivy

Go to download

Spoon is a tool for meta-programming, analysis and transformation of Java programs.

There is a newer version: 11.1.1-beta-14
Show newest version
/*
 * SPDX-License-Identifier: (MIT OR CECILL-C)
 *
 * Copyright (C) 2006-2023 INRIA and contributors
 *
 * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) or the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon.
 */
package spoon.reflect.meta.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import spoon.SpoonException;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.meta.RoleHandler;
import spoon.reflect.path.CtRole;

/**
 * Provides a {@link RoleHandler} implementation for the pair of {@link CtElement} implementation and {@link CtRole}
 * The returned {@link RoleHandler} can be then used to manipulate value of attribute represented by {@link CtRole} on the {@link CtElement} instance
 */
public class RoleHandlerHelper {
	private RoleHandlerHelper() {
	}

	private static Map, List> roleHandlersByClass = new HashMap<>();

	private static final Map> roleHandlers = new EnumMap<>(CtRole.class);
	static {
		for (RoleHandler rh : ModelRoleHandlers.roleHandlers) {
			roleHandlers.computeIfAbsent(rh.getRole(), role -> new ArrayList<>()).add(rh);
		}
		Comparator cmp = (a, b) -> a.getTargetType().isAssignableFrom(b.getTargetType()) ? 1 : -1;
		for (RoleHandler rh : ModelRoleHandlers.roleHandlers) {
			roleHandlers.get(rh.getRole()).sort(cmp);
		}
	}

	/**
	 * @param targetClass the class of the to be manipulated node
	 * @param role defines the to be manipulated attribute
	 * @return {@link RoleHandler} implementation which knows how to manipulate the attribute of {@link CtRole} on `targetClass`
	 * or throws exception if such role doesn't exist on the `targetClass`
	 */
	public static RoleHandler getRoleHandler(Class targetClass, CtRole role) {
		RoleHandler rh = getOptionalRoleHandler(targetClass, role);
		if (rh == null) {
			throw new SpoonException("The element of class " + targetClass + " does not have CtRole." + role.name());
		}
		return rh;
	}

	/**
	 * @param targetClass the Class of the to be manipulated node
	 * @param role defines the to be manipulated attribute
	 * @return {@link RoleHandler} implementation, which knows how to manipulate the attribute of {@link CtRole} on `targetClass`
	 * or returns null if such role doesn't exist on the `targetClass`
	 */
	public static RoleHandler getOptionalRoleHandler(Class targetClass, CtRole role) {
		List handlers = roleHandlers.get(role);
		for (RoleHandler ctRoleHandler : handlers) {
			if (ctRoleHandler.getTargetType().isAssignableFrom(targetClass)) {
				return ctRoleHandler;
			}
		}
		return null;
	}

	/**
	 * @param targetClass a Class whose handlers we are looking for
	 * @return all {@link RoleHandler}s available for the `targetClass`
	 */
	public static List getRoleHandlers(Class targetClass) {
		List handlers = roleHandlersByClass.get(targetClass);
		if (handlers == null) {
			List modifiableHandlers = new ArrayList<>();
			for (CtRole role : CtRole.values()) {
				RoleHandler roleHandler = getOptionalRoleHandler(targetClass, role);
				if (roleHandler != null) {
					modifiableHandlers.add(roleHandler);
				}
			}
			handlers = Collections.unmodifiableList(modifiableHandlers);
			roleHandlersByClass.put(targetClass, handlers);
		}
		return handlers;
	}

	/**
	 * @param consumer is called for each {@link RoleHandler} of SpoonModel
	 */
	public static void forEachRoleHandler(Consumer consumer) {
		for (List list : roleHandlers.values()) {
			for (RoleHandler roleHandler : list) {
				consumer.accept(roleHandler);
			}
		}
	}

	/**
	 * @param element the {@link CtElement} whose relation from `element.getParent()` to `element` is needed.
	 * @return {@link RoleHandler} handling relation from `element.getParent()` to `element`
	 */
	public static RoleHandler getRoleHandlerWrtParent(CtElement element) {
		if (!element.isParentInitialized()) {
			return null;
		}
		CtElement parent = element.getParent();
		CtRole roleInParent = element.getRoleInParent();
		if (roleInParent == null) {
			return null;
		}
		return getRoleHandler(parent.getClass(), roleInParent);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy