// SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 icelimetea * Copyright (C) 2022 solonovamax * Copyright (C) 2022 TheKodeToad * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. * * As a special exception, the copyright holders of this library give * you permission to link this library with independent modules to * produce an executable, regardless of the license terms of these * independent modules, and to copy and distribute the resulting * executable under terms of your choice, provided that you also meet, * for each linked independent module, the terms and conditions of the * license of that module. An independent module is a module which is * not derived from or based on this library. If you modify this * library, you may extend this exception to your version of the * library, but you are not obliged to do so. If you do not wish to do * so, delete this exception statement from your version. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * * Copyright 2013-2021 MultiMC Contributors * * 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.prismlauncher.utils; import java.applet.Applet; import java.io.File; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.prismlauncher.utils.logging.Log; public final class ReflectionUtils { private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static final ClassLoader LOADER = ClassLoader.getSystemClassLoader(); /** * Construct a Java applet by its class name. * * @param clazz The class name * @return The applet instance * @throws Throwable */ public static Applet createAppletClass(String clazz) throws Throwable { Class appletClass = LOADER.loadClass(clazz); MethodHandle appletConstructor = LOOKUP.findConstructor(appletClass, MethodType.methodType(void.class)); return (Applet) appletConstructor.invoke(); } /** * Best guess of the game directory field within net.minecraft.client.Minecraft. * Designed for legacy versions - newer versions do not use a static field. * * @param clazz The class * @return The first field matching criteria */ public static Field findMinecraftGameDirField(Class clazz) { Log.debug("Resolving minecraft game directory field"); // search for private static File for (Field field : clazz.getDeclaredFields()) { if (field.getType() != File.class) { continue; } int fieldModifiers = field.getModifiers(); if (!Modifier.isStatic(fieldModifiers)) { Log.debug("Rejecting field " + field.getName() + " because it is not static"); continue; } if (!Modifier.isPrivate(fieldModifiers)) { Log.debug("Rejecting field " + field.getName() + " because it is not private"); continue; } if (Modifier.isFinal(fieldModifiers)) { Log.debug("Rejecting field " + field.getName() + " because it is final"); continue; } Log.debug("Identified field " + field.getName() + " to match conditions for game directory field"); return field; } return null; } /** * Gets the main method within a class. * * @param clazz The class * @return A method matching the descriptor of a main method * @throws ClassNotFoundException * @throws NoSuchMethodException * @throws IllegalAccessException */ public static MethodHandle findMainMethod(Class clazz) throws NoSuchMethodException, IllegalAccessException { return LOOKUP.findStatic(clazz, "main", MethodType.methodType(void.class, String[].class)); } /** * Gets the main method within a class by its name. * * @param clazz The class name * @return A method matching the descriptor of a main method * @throws ClassNotFoundException * @throws NoSuchMethodException * @throws IllegalAccessException */ public static MethodHandle findMainMethod(String clazz) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException { return findMainMethod(LOADER.loadClass(clazz)); } }