I am trying to develop a dynamic Factory Class, where Factory Class does not know the factories, I will put the code so that the question is clearer.
App.java:
package br.com.factory;
public class App {
public static void main(String[] args) {
Product product = ProductFactory.createProduct("Xiaomi", "MI XX");
if (product != null) {
System.out.println(product.getName());
}
}
}
Product.java:
package br.com.factory;
public interface Product {
public String getName();
}
ProductFactory.java:
package br.com.factory;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public class ProductFactory {
private static HashMap<String, Map<String, Supplier<Product>>> registries = new HashMap<>();
private ProductFactory(){}
static {
ClassLoaderInitializer.initialize(ProductSupplier.class);
}
public static Product createProduct(String manufacturer, String model) {
Map<String, Supplier<Product>> manufacturers = registries.getOrDefault(manufacturer, null);
if (manufacturers != null){
Supplier<Product> suppliers = manufacturers.getOrDefault(model, null);
if (suppliers != null) {
return suppliers.get();
}
}
return null;
}
public static void registerFactory(String manufacturer, String model, Supplier<Product> supplier) {
registries
.computeIfAbsent(manufacturer, p -> new HashMap<>())
.putIfAbsent(model, supplier);
}
}
ProductSupplier.java:
package br.com.factory;
import java.util.function.Supplier;
public interface ProductSupplier extends Supplier<Product> {
}
XiaomiFactory.java:
package br.com.factory.xiaomi;
import br.com.factory.Product;
import br.com.factory.ProductFactory;
import br.com.factory.ProductSupplier;
public class XiaomiFactory implements ProductSupplier {
static {
ProductFactory.registerFactory("Xiaomi", "MI XX", XiamoMiXX::new);
}
private XiaomiFactory() {
}
#Override
public Product get() {
return new XiamoMiXX();
}
}
class XiamoMiXX implements Product {
#Override
public String getName() {
return "Xiaomi Mi XX";
}
}
ClassLoaderInitializer.java:
package br.com.factory;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
public class ClassLoaderInitializer {
private ClassLoaderInitializer() {
}
public static void initialize(Class<?> parentClass) {
try {
Enumeration<URL> resources = ClassLoaderInitializer.class.getClassLoader().getResources("");
while (resources.hasMoreElements()) {
URL nextElement = resources.nextElement();
try (URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { nextElement });) {
URL[] urLs = urlClassLoader.getURLs();
for (URL u : urLs) {
try {
File file = new File(u.toURI());
initializeClass(file, file, urlClassLoader, parentClass);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void initializeClass(File root, File file, ClassLoader loader, Class<?> parentClass) {
if (file.isDirectory()) {
File[] listFiles = file.listFiles();
for (File f : listFiles) {
initializeClass(root, f, loader, parentClass);
}
} else {
if (file.getName().toUpperCase().endsWith(".class".toUpperCase())) {
try {
String fileName = file.toString();
String className = fileName.substring(root.toString().length() + 1,
fileName.toUpperCase().lastIndexOf(".class".toUpperCase())).replace(File.separator, ".");
Class<?> clazz = Class.forName(className, false, loader);
if (clazz.isAssignableFrom(parentClass)) {
Class.forName(className, true, loader);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
The problem occurs in the initializeClass method,
more precisely in:
Class <?> Clazz = Class.forName (className, false, loader);
if (clazz.isAssignableFrom (parentClass)) {
Class.forName (className, true, loader);
}
the idea of the ClassLoaderInitializer class is to initialize the classes that inherit from a given class "Class <?> parentClass"
but when I call the method
Class.forName (className, true, loader);
for the second time, passing true in the second parameter, the class is not initialized.
if I call:
Class.forName (className, true, loader);
directly, the initializeClass method will initialize all classes, what I would not like to happen.
is there any outside of me explicitly initializing (forcing) the class specifies?
Use ServiceLoader
ServiceLoader allows you to register services using metadata in the META-INF/services/ folder. It allows you to use a Java API to register all your services at once. It's better than trying to do it yourself, especially since it's standardized and doesn't require "magic" to get registered. Magic which might be broken in Java 9 and later with the introduction of modules.
This is how you should use it:
ProductSupplier.java
public interface ProductSupplier extends Supplier<Product> {
// Add these methods
String getManufacturer();
String getModel();
}
ProductFactory.java
public class ProductFactory {
private static final Map<List<String>, ProductSupplier> SUPPLIERS;
static {
var suppliers = new HashMap<List<String>, ProductSupplier>();
for (var supplier : ServiceLoader.load(ProductSupplier.class)) { // Yes, it's as easy as this.
var key = List.of(supplier.getManufacturer(), supplier.getModel());
suppliers.put(key, supplier);
}
SUPPLIERS = Map.copyOf(suppliers);
}
public static Product createProduct(String manufacturer, String model) {
var key = List.of(manufacturer, model);
var supplier = suppliers.getOrDefault(key, () -> null);
return supplier.get();
}
}
XiaomiFactory.java
public class XiaomiFactory implements ProductSupplier {
#Override public String getManufacturer() { return "Xiaomi"; }
#Override public String getModel() { return "Mi XX"; }
#Override public Product get() { return new XiaomiMiXX(); }
}
In META-INF/services/com.br.factory.ProductSupplier:
com.br.factory.xiaomi.XiaomiFactory
com.br.factory.samsung.SamsungFactory # Need to create
com.br.factory.apple.AppleFactory # Need to create
Related
I have a java jar file contain interface named IOperator like this :
public interface IOperator {
String execute(Map<String, String> parameters);
boolean isSuccess();
}
now in groovy script (in single file):
public class ClassA {
}
public class ClassB {
}
public class classC implements IOperator {
#Override
String execute(Map<String, String> parameters) {
ClassA classA = new ClassA();
ClassB classB = new ClassB();
return null
}
#Override
boolean isSuccess() {
return false
}
}
Is there any way scan this groovy script to find that specific class implemented IOperator and invoke execute method ?
Note: I want do it in Java code.
Finally i found answer :
public class OperatorManager {
public static void run(File scriptFile) {
try {
GroovyScriptEngineImpl engine = (GroovyScriptEngineImpl) new GroovyScriptEngineFactory().getScriptEngine();
GroovyClassLoader classLoader = new GroovyClassLoader();
classLoader.parseClass(new GroovyCodeSource(scriptFile));
engine.setClassLoader(classLoader);
Class<?>[] loadedClasses = engine.getClassLoader().getLoadedClasses();
Class<?> operatorImplClass = Arrays.stream(loadedClasses)
.filter(IOperator.class::isAssignableFrom)
.findFirst().orElse(null);
if (operatorImplClass != null) {
String result = invokeMethod(operatorImplClass);
System.out.println(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static String invokeMethod(Class<?> item) {
try {
Object instance = item.getConstructor().newInstance();
Method execute = item.getDeclaredMethod("execute", Map.class);
return (String) execute.invoke(instance, new Object[]{null});
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
I am wrapping legacy code with some REST/jackson capabilities. In particular let's say I have an interface called LegacyObject
interface LegacyObject {
Integer getAge(); //could throw UnsupportedOperationException
String getDesc();
String getName(); //May throw RuntimeException
//about 200+ other methods.
}
The implementation is a legacy class and assume cannot be changed. My REST service has an endpoint which converts LegacyObject to JSON. The only problem being that this conversion fails fully whenever one of the getters throws an exception. What I need is a json like the below (assuming getAge(), getDesc() worked okay but getName() threw runtimeexception)
{"age": 40, "desc": "some description", "unsupportedFields": ["name"]}
Basically a way to capture all fields that failed serialization and then report at the end.
An interceptor like thing might work for me but if anyone has some code examples that would be great!
Since there are 200+ methods in the interface, below a solution with Proxies.
This code does not guarantee that the "getUnsupportedFields" method is called last (and thus still some exceptions may occur after)
public interface LegacyObject {
Integer getAge(); //could throw UnsupportedOperationException
String getDesc();
String getName(); //May throw RuntimeException
//about 200+ other methods.
}
import java.util.List;
public interface ExtendedLegacyObject extends LegacyObject {
List<String> getUnsupportedFields();
}
public class ExceptionLegacyObject implements LegacyObject {
#Override
public Integer getAge() {
return 40;
}
#Override
public String getDesc() {
return "some description";
}
#Override
public String getName() {
throw new RuntimeException();
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
public class LegacyObjectHandler implements InvocationHandler {
private static final Logger LOG = Logger.getLogger(LegacyObjectHandler.class);
private final List<String> unsupportedFields = new ArrayList<>();
private final LegacyObject legacyObject;
public LegacyObjectHandler(LegacyObject legacyObject) {
this.legacyObject = legacyObject;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("getUnsupportedFields".equals(method.getName())) {
return unsupportedFields;
} else {
try {
return method.invoke(legacyObject, args);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
LOG.error(cause.getMessage(), cause);
unsupportedFields.add(method.getName());
Class<?> returnType = method.getReturnType();
if (returnType.isPrimitive()) {
if (returnType.isAssignableFrom(boolean.class)) {
return false;
} else if (returnType.isAssignableFrom(byte.class)) {
return (byte) 0;
} else if (returnType.isAssignableFrom(short.class)) {
return (short) 0;
} else if (returnType.isAssignableFrom(int.class)) {
return 0;
} else if (returnType.isAssignableFrom(long.class)) {
return 0L;
} else if (returnType.isAssignableFrom(float.class)) {
return 0F;
} else if (returnType.isAssignableFrom(double.class)) {
return 0D;
} else if (returnType.isAssignableFrom(char.class)) {
return (char) 0;
} else {
return null;
}
} else {
return null;
}
}
}
}
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Proxy;
public class JacksonTest {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
ExceptionLegacyObject exceptionLegacyObject = new ExceptionLegacyObject();
ExtendedLegacyObject proxy = (ExtendedLegacyObject) Proxy.newProxyInstance(
LegacyObject.class.getClassLoader(),
new Class[] { ExtendedLegacyObject.class },
new LegacyObjectHandler(exceptionLegacyObject)
);
System.out.println(mapper.writeValueAsString(proxy));
}
}
I used a variation of what #toongeorges suggested above. Here is a utility class which will do a "exception safe" convert to JSON. There will be an extra element in the returned JSON called "exceptionMessages" which contains the properties that failed json serialisation (or the method name if it is NOT a Java bean property). This can be changed to return a Pair of JsonNode one for the object and one for exceptionMessages if that style suits you better
import static java.util.stream.Collectors.toMap;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Stream;
import org.apache.commons.lang3.exception.ExceptionUtils;
public abstract class JsonUtils {
private static ObjectMapper mapper = new ObjectMapper();
/**
* This is only useful in the context of converting a object whose methods could throw exceptions
* into JSON. By default a "getName" method that throws an exception will fail the whole
* serialization however with this method such exceptions will be swallowed and there will be a
* "exceptionMessages" element in the returned JSON which contains all failures
*
* To be used only when working with legacy code.
*/
#SuppressWarnings("unchecked")
public static <U> ObjectNode exceptionSafeWrite(Class<U> sourceClazz, U obj, boolean prettyPrint) {
GuardedInvocationHandler handler = new GuardedInvocationHandler(obj);
U proxiedObject = (U) Proxy
.newProxyInstance(sourceClazz.getClassLoader(), new Class<?>[]{sourceClazz}, handler);
ObjectNode originalNode = mapper.convertValue(proxiedObject, ObjectNode.class);
ObjectNode exceptionMessages = mapper.convertValue(handler.getExceptionMessagesForJson(), ObjectNode.class);
originalNode.put("exceptionMessages", exceptionMessages);
return originalNode;
}
private static class GuardedInvocationHandler implements InvocationHandler {
private final Object target;
private Map<Method, Throwable> exceptionMap = new LinkedHashMap<>();
private Map<Method, String> methodToPropertyNameMap;
private GuardedInvocationHandler(Object target) {
this.target = target;
this.methodToPropertyNameMap = methodToPropertyNameMap(target.getClass());
}
private static Map<Method, String> methodToPropertyNameMap(Class<?> clazz) {
try {
return Stream.of(Introspector.getBeanInfo(clazz).getPropertyDescriptors())
.collect(toMap(d -> d.getReadMethod(), d -> d.getName()));
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return method.invoke(target, args);
} catch (InvocationTargetException e) {
exceptionMap.put(method, e.getTargetException());
return null;
} catch (Exception e) {
exceptionMap.put(method, e);
return null;
}
}
public Map<String, String> getExceptionMessagesForJson() {
return exceptionMap.entrySet().stream().collect(
toMap(e -> methodToPropertyNameMap.getOrDefault(e.getKey(), e.getKey().getName()),
e -> ExceptionUtils.getMessage(e.getValue())));
}
}
}
I'm trying to create an object using reflection like this
(maybe this is not a good architecture but I'm just doing some tests)
package com.interfaces;
public interface IEmployee {
List<entities.Employee> getEmployees();
}
then
package com.personnel;
public class Employee implements IEmployee{
public Employee(){}
public List<entities.Employee> getEmployees(){
...
}
}
then in another class
package com.factory;
import java.lang.reflect.Constructor;
public final class EmployeeFactory {
private static String path = "com.personnel";
public EmployeeFactory() {}
public static interfaces.IEmployee CreateEmployee(){
String className = path + ".Employee";
try {
Class<?> cls = Class.forName(className);
Object object = cls.newInstance();
return (interfaces.IEmployee)object;
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
}
then in another class
public final class PersonnelService {
private static interfaces.IEmployee employeeFactory = com.factory.EmployeeFactory.CreateEmployee();
public List<entities.Employee> getEmployees(){
return employeeFactory.getEmployees();
}
}
finally in my main method
public static void main(String[] args) {
List<entities.Employee> employees = new com.services.PersonnelService().getEmployees();
for(entities.Employee employee : employees){
System.out.println(employee.getEmployeeName());
}
when the code arrives to Class cls = Class.forName(className) it throws the exception message "com.personnel.Employee.(java.lang.String)" with "NoSuchMethodException".
UPDATE
I found the problem. In fact, it was a bad naming convention. I had a serializable Employee class (my pojo) and an Employee class which implements my interface IEmployee which is intended to perform DB operations. I renamed this last one as EmployeeDAL and it worked. Even I defined the full class name as you can see in the example, it looks like that I was trying to instantiate my serializable pojo (I still don't get it, but...). Thanks for your time.
I tried to reproduce your code and not found any error on this code. I only get NoSuchMethodException message when I change Employee constructor with String argument
package com.agit.example.test;
import java.util.ArrayList;
import java.util.List;
public class TestClass {
public static void main(String[] args) {
List<Employee> employees = new PersonnelService().getEmployees();
for(Employee employee : employees){
System.out.println(employee);
}
}
}
interface IEmployee {
List<Employee> getEmployees();
}
class Employee implements IEmployee{
public Employee(){}
public List<Employee> getEmployees(){
List<Employee> x = new ArrayList<>();
x.add(this);
return x;
}
}
final class EmployeeFactory {
private static String path = "com.agit.example.test";
public EmployeeFactory() {}
public static IEmployee CreateEmployee(){
String className = path + ".Employee";
try {
Class<?> cls = Class.forName(className);
Object object = cls.newInstance();
return (IEmployee)object;
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
}
final class PersonnelService {
private static IEmployee employeeFactory = EmployeeFactory.CreateEmployee();
public List<Employee> getEmployees(){
return employeeFactory.getEmployees();
}
}
I have several child classes extending an abstract parent class. I want the parent class to have a static ArrayList holding instances of each child. If possible, I would like to be able to add more child classes without having to change the parent class's code.
One solution I came up with is to give each of the child classes a static block that will add an instance of itself to the ArrayList. The only problem with this is that I then need to make some call to each child to get it to load and run the block.
abstract public class Parent {
protected static ArrayList<Parent> children = new ArrayList<Parent>();
}
public class ChildA extends Parent {
static {
children.add(new ChildA());
}
}
public class ChildB extends Parent {
static {
children.add(new ChildB());
}
}
Is there a way around this? Can I load a class without making a call to it? Would there be any better ways of doing this?
Edit:
This is actually for a tile based game. I have an abstract "Tile" class and an arbitrary number of tile types extending it. I would like to be able to easily add new tiles to the game without having to change the code all over the place. If you have a better idea for how to do this, I am open to suggestion.
You can do it outside the class hierarchy. Have a utility function that uses reflection to find all descendants of Parent and then adds them to your list.
Your motivation for wanting to do this is unclear, but there are solutions that don't necessarily involve reflection.
Shift the responsibility for creating the child classes into a factory class. In that factory class, insert the children classes into your list as well.
Here's a snippet that could do just that. Remember: because your list is bound to Parent, you will have to cast to the correct child class type to actually use the classes later.
public final class ChildFactory {
private static ChildFactory instance = new ChildFactory();
private ChildFactory() {
}
public <C extends Parent> C generateChild(Class<C> childClass) {
try {
final C child = childClass.newInstance();
Parent.children.add(child);
return child;
} catch(InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static ChildFactory getInstance() {
return instance;
}
}
I think threre might be an easier way to do it but this class may be usefull:
package classFinder;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassFinder {
protected static Class<?> getClass(String prefix, String classPath)
throws ClassNotFoundException {
if (!classPath.endsWith(".class") || !classPath.startsWith(prefix)) {
return null;
}
return Class.forName(classPath.substring(prefix.length(),
classPath.length() - ".class".length()).replace('/', '.'));
}
protected static Class<?> getClass(File rootFile, File classFile)
throws ClassNotFoundException {
return getClass(rootFile.getPath() + '/', classFile.getPath());
}
#SuppressWarnings("unchecked")
protected static <T> Set<Class<T>> searchAllSubclassesInDirectory(
File rootFile, File searchFile, Class<?> cls,
boolean abstractClasses) throws ClassFinderException {
Set<Class<T>> result = new HashSet<Class<T>>();
if (searchFile.isDirectory()) {
for (File file : searchFile.listFiles()) {
result.addAll(ClassFinder.<T> searchAllSubclasses(
rootFile.getPath(), file.getPath(), cls,
abstractClasses));
}
return result;
}
String fileName = searchFile.getName();
if (!fileName.endsWith(".class")) {
return result;
}
try {
Class<?> entry = getClass(rootFile, searchFile);
if (entry != null
&& (abstractClasses || !Modifier.isAbstract(entry
.getModifiers()))) {
Class<?> superClass = entry;
while (!((superClass = superClass.getSuperclass()) == null)) {
if (superClass.equals(cls)) {
result.add((Class<T>) entry);
return result;
}
}
}
return result;
} catch (ClassNotFoundException e) {
// e.printStackTrace(); //DEBUG only
return result;
}
}
#SuppressWarnings("unchecked")
protected static <T> Set<Class<T>> searchAllSubclassesInJar(File jar,
Class<?> cls, boolean abstractClasses) {
Set<Class<T>> result = new HashSet<Class<T>>();
try {
JarFile jarFile = new JarFile(jar);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry file = entries.nextElement();
if (file.isDirectory()) {
continue;
}
Class<?> entry = getClass("", file.getName());
if (entry != null
&& (abstractClasses || !Modifier.isAbstract(entry
.getModifiers()))) {
Class<?> superClass = entry;
while (!((superClass = superClass.getSuperclass()) == null)) {
if (superClass.equals(cls)) {
result.add((Class<T>) entry);
}
}
}
}
jarFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
protected static <T> Set<Class<T>> searchAllSubclasses(String rootPath,
String searchPath, Class<?> cls, boolean abstractClasses)
throws ClassFinderException {
if (searchPath.endsWith(".jar")) {
return searchAllSubclassesInJar(new File(searchPath), cls,
abstractClasses);
// return new HashSet<Class<T>>();
} else {
return searchAllSubclassesInDirectory(new File(rootPath), new File(
searchPath), cls, abstractClasses);
}
}
// TODO create public method to search inside a not root directory/package
public static <T> Set<Class<T>> searchAllSubclasses(Class<?> cls,
boolean abstractClasses) throws ClassFinderException {
Set<Class<T>> result = new HashSet<Class<T>>();
String classpath = System.getProperty("java.class.path");
for (String path : classpath
.split(System.getProperty("path.separator"))) {
result.addAll(ClassFinder.<T> searchAllSubclasses(path, path, cls,
abstractClasses));
}
return result;
// return ClassFinder.<T> searchAllSubclasses(ROOT_URL, cls,
// abstractClasses, "");
}
}
If you're working with a standard java desktop application it may work.
This class searches for implementations of a given superclass on a your program directory tree. Works for jar files too.
You can then initialize your static field:
abstract public class Parent {
protected static Set<Parent> children = ClassFinder
.<Parent> searchAllSubclasses(Parent.class, true);
}
So I'm working on a plugin loader for a game and what it does is load plugins (class objects) from a .jar inside a folder, then add them to an ArrayList (so users can make their own mods). But my java experience isn't the best :/ So far it gets the classes in the jar but I need to check what methods are in the class (such as the constructor for labeling). Or if someone knows a better way to do this. Any help would be appreciated.
Plugin.java:
package me.rigamortis.faurax.plugin;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import net.minecraft.client.Minecraft;
import me.rigamortis.faurax.core.Core;
public class Plugin {
public Minecraft mc = Minecraft.getMinecraft();
final File folder = new File(mc.mcDataDir + File.separator + "Faurax/Plugins");
public String jar;
public static String className;
private String name;
private String desc;
private int color;
private int key;
public Plugin() {
if(!folder.exists())
folder.mkdirs();
loadPlugins(folder);
if(folder != null)
getClassNames(folder);
}
public void setName(String newName) {
name = newName;
}
public void setDesc(String newDesc) {
desc = newDesc;
}
public void setColor(int newColor) {
color = newColor;
}
public void setKey(int newKey) {
key = newKey;
}
public String getName() {
return this.name;
}
public String getDesc() {
return this.desc;
}
public int getKey() {
return this.key;
}
public int getColor() {
return this.color;
}
/**
* A hook for plugins
*/
public void onTick() {}
public void loadPlugins(final File folder) {
try{
for (final File fileEntry : folder.listFiles()) {
if ( !fileEntry.isDirectory()) {
if(fileEntry.getName().endsWith(".jar")){
jar = fileEntry.getName();
Core.logNormal("Loading " + fileEntry.getName());
}
}
}
}
catch(Exception e) {
Core.logError("Error? jar isin't a plugin.");
e.printStackTrace();
}
}
public void getClassNames(final File dir) {
try{
ZipInputStream zip = new ZipInputStream(new FileInputStream(dir + File.seperator + jar));
for(ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry())
if(entry.getName().endsWith(".class") && !entry.isDirectory()) {
Core.logNormal("Found "+entry);
className = entry.toString();
}
}
catch(IOException e){
e.printStackTrace();
}
}
}
PluginLoader.java:
package me.rigamortis.faurax.plugin;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import me.rigamortis.faurax.core.Core;
public class PluginLoader {
public static List<Plugin> plugins = new ArrayList<Plugin>();
public PluginLoader() {
loadPlugins();
}
public void loadPlugins() {}
}
I answered a similar question to this not too long ago. Here's the code to get all methods from a given class, I think it's fairly self-explanatory:
void foo(Object o)
{
Class<?> c = o.getClass();
for (Method m : c.getDeclaredMethods())
{
//do whatever
}
}
This takes advantage of the Java's Reflection API. You can read more about it here.