Java tutorial
/* * Copyright 2018 MovingBlocks * * 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.terasology.documentation.apiScraper; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.module.ExternalApiWhitelist; import org.terasology.engine.module.ModuleManager; import org.terasology.module.ModuleEnvironment; import org.terasology.module.sandbox.API; import org.terasology.testUtil.ModuleManagerFactory; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.stream.Collectors; /** * Enumerates all classes, interfaces and packages that are annotated with {@link API} and their public methods and * constructors. */ final class CompleteApiScraper { private static final String TERASOLOGY_API_CLASS_CATEGORY = "terasology engine"; private static final String EXTERNAL = "external"; private static final Logger logger = LoggerFactory.getLogger(CompleteApiScraper.class); private CompleteApiScraper() { // Private constructor, utility class } /** * * @return Project's Packages, Interfaces, Classes and Methods * @throws Exception if the module environment cannot be loaded */ static StringBuffer getApi() throws Exception { ModuleManager moduleManager = ModuleManagerFactory.create(); ModuleEnvironment environment = moduleManager.getEnvironment(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Multimap<String, String> api = Multimaps.newMultimap(new HashMap<String, Collection<String>>(), ArrayList::new); for (Class<?> apiClass : environment.getTypesAnnotatedWith(API.class)) { boolean isPackage = apiClass.isSynthetic(); URL location; String category; String apiPackage = ""; if (isPackage) { apiPackage = apiClass.getPackage().getName(); location = classLoader.getResource(apiPackage.replace('.', '/')); } else { location = apiClass.getResource('/' + apiClass.getName().replace('.', '/') + ".class"); } if (location == null) { logger.error("Failed to get a class/package location, skipping " + apiClass); continue; } switch (location.getProtocol()) { case "jar": // Find out what jar it came from and consider that the category String categoryFragment = location.getPath(); int bang = categoryFragment.lastIndexOf("!"); int hyphen = categoryFragment.lastIndexOf("-", bang); int slash = categoryFragment.lastIndexOf("/", hyphen); category = categoryFragment.substring(slash + 1, hyphen); if (isPackage) { api.put(category, apiPackage + " (PACKAGE)"); } else { addToApi(category, apiClass, api); } break; case "file": // If file based we know it is local so organize it like that category = TERASOLOGY_API_CLASS_CATEGORY; if (isPackage) { api.put(category, apiPackage + " (PACKAGE)"); } else { addToApi(category, apiClass, api); } break; default: logger.error("Unknown protocol for: " + apiClass + ", came from " + location); } } api.putAll(EXTERNAL, ExternalApiWhitelist.CLASSES.stream().map(clazz -> clazz.getName() + " (CLASS)") .collect(Collectors.toSet())); api.putAll(EXTERNAL, ExternalApiWhitelist.PACKAGES.stream().map(packagee -> packagee + " (PACKAGE)") .collect(Collectors.toSet())); //Puts the information in the StringBuffer StringBuffer stringApi = new StringBuffer(); stringApi.append("# Modding API:\n"); for (String key : api.keySet()) { stringApi.append("## "); stringApi.append(key); stringApi.append("\n"); for (String value : api.get(key)) { stringApi.append("* "); stringApi.append(value); stringApi.append("\n"); } stringApi.append("\n"); } return stringApi; } /** * Adds interface or class and their methods and constructors to api * are also added. * @param category where the apiClass belongs * @param apiClass the class or interface to be added * @param api that maps category to classes/interface/methods */ private static void addToApi(String category, Class<?> apiClass, Multimap<String, String> api) { String className = apiClass.getName(); String type; if (apiClass.isInterface()) { type = " (INTERFACE)"; } else { int modifier = apiClass.getModifiers(); if (Modifier.isAbstract(modifier)) { type = " (ABSTRACT CLASS)"; } else { type = " (CLASS)"; } } api.put(category, className + type); //Add current apiClass's constructors Constructor[] constructors = apiClass.getDeclaredConstructors(); for (Constructor constructor : constructors) { api.put(category, " - " + constructor.getName() + " (CONSTRUCTOR)"); api.put(category, " -- " + Arrays.toString(constructor.getParameterTypes()) + " (PARAMETERS)"); } //Add current apiClass's methods Method[] methods = apiClass.getDeclaredMethods(); for (Method method : methods) { if (!method.isDefault() && !method.isBridge() && !method.isSynthetic()) { //Check if it's an abstract method int modifier = method.getModifiers(); if (Modifier.isAbstract(modifier)) { type = " (ABSTRACT METHOD)"; } else { type = " (METHOD)"; } //Adds method's information api.put(category, " - " + method.getName() + type); api.put(category, " -- " + method.getReturnType() + " (RETURN)"); api.put(category, " -- " + Arrays.toString(method.getParameterTypes()) + " (PARAMETERS)"); api.put(category, " -- " + Arrays.toString(method.getExceptionTypes()) + " (EXCEPTIONS)"); } else if (method.isDefault() && apiClass.isInterface()) { api.put(category, " - " + method.getName() + " (DEFAULT METHOD)"); api.put(category, " -- " + method.getReturnType() + " (RETURN)"); api.put(category, " -- " + Arrays.toString(method.getParameterTypes()) + " (PARAMETERS)"); api.put(category, " -- " + Arrays.toString(method.getExceptionTypes()) + " (EXCEPTIONS)"); } } } }