UIDefaultsLoader:

- support `{instance}com.myapp.MyClass` to instantiate any public class with public no-arg constructor
- support `{class}com.myapp.MyClass`
- support loading addon classes from different classloaders (e.g. in NetBeans)
This commit is contained in:
Karl Tauber
2019-12-07 17:53:59 +01:00
parent b4c1a97687
commit 46f0393648

View File

@@ -22,6 +22,7 @@ import java.awt.Insets;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -77,6 +78,8 @@ class UIDefaultsLoader
static void loadDefaultsFromProperties( List<Class<?>> lafClasses, UIDefaults defaults ) { static void loadDefaultsFromProperties( List<Class<?>> lafClasses, UIDefaults defaults ) {
try { try {
List<ClassLoader> addonClassLoaders = new ArrayList<>();
// load properties files // load properties files
Properties properties = new Properties(); Properties properties = new Properties();
ServiceLoader<FlatDefaultsAddon> addonLoader = ServiceLoader.load( FlatDefaultsAddon.class ); ServiceLoader<FlatDefaultsAddon> addonLoader = ServiceLoader.load( FlatDefaultsAddon.class );
@@ -94,6 +97,10 @@ class UIDefaultsLoader
if( in != null ) if( in != null )
properties.load( in ); properties.load( in );
} }
ClassLoader addonClassLoader = addon.getClass().getClassLoader();
if( !addonClassLoaders.contains( addonClassLoader ) )
addonClassLoaders.add( addonClassLoader );
} }
} }
@@ -131,7 +138,7 @@ class UIDefaultsLoader
String value = resolveValue( properties, (String) e.getValue() ); String value = resolveValue( properties, (String) e.getValue() );
try { try {
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver ) ); globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver, addonClassLoaders ) );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
logParseError( key, value, ex ); logParseError( key, value, ex );
} }
@@ -156,7 +163,7 @@ class UIDefaultsLoader
String value = resolveValue( properties, (String) e.getValue() ); String value = resolveValue( properties, (String) e.getValue() );
try { try {
defaults.put( key, parseValue( key, value, resolver ) ); defaults.put( key, parseValue( key, value, resolver, addonClassLoaders ) );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
logParseError( key, value, ex ); logParseError( key, value, ex );
} }
@@ -195,13 +202,13 @@ class UIDefaultsLoader
return resolveValue( properties, newValue ); return resolveValue( properties, newValue );
} }
private enum ValueType { UNKNOWN, STRING, INTEGER, BORDER, ICON, INSETS, SIZE, COLOR, SCALEDNUMBER } private enum ValueType { UNKNOWN, STRING, INTEGER, BORDER, ICON, INSETS, SIZE, COLOR, SCALEDNUMBER, INSTANCE, CLASS }
static Object parseValue( String key, String value ) { static Object parseValue( String key, String value ) {
return parseValue( key, value, v -> v ); return parseValue( key, value, v -> v, Collections.emptyList() );
} }
private static Object parseValue( String key, String value, Function<String, String> resolver ) { private static Object parseValue( String key, String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
value = value.trim(); value = value.trim();
// null, false, true // null, false, true
@@ -254,12 +261,14 @@ class UIDefaultsLoader
switch( valueType ) { switch( valueType ) {
case STRING: return value; case STRING: return value;
case INTEGER: return parseInteger( value, true ); case INTEGER: return parseInteger( value, true );
case BORDER: return parseBorder( value, resolver ); case BORDER: return parseBorder( value, resolver, addonClassLoaders );
case ICON: return parseInstance( value ); case ICON: return parseInstance( value, addonClassLoaders );
case INSETS: return parseInsets( value ); case INSETS: return parseInsets( value );
case SIZE: return parseSize( value ); case SIZE: return parseSize( value );
case COLOR: return parseColorOrFunction( value, true ); case COLOR: return parseColorOrFunction( value, true );
case SCALEDNUMBER: return parseScaledNumber( value ); case SCALEDNUMBER: return parseScaledNumber( value );
case INSTANCE: return parseInstance( value, addonClassLoaders );
case CLASS: return parseClass( value, addonClassLoaders );
case UNKNOWN: case UNKNOWN:
default: default:
// colors // colors
@@ -277,7 +286,7 @@ class UIDefaultsLoader
} }
} }
private static Object parseBorder( String value, Function<String, String> resolver ) { private static Object parseBorder( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
if( value.indexOf( ',' ) >= 0 ) { if( value.indexOf( ',' ) >= 0 ) {
// top,left,bottom,right[,lineColor] // top,left,bottom,right[,lineColor]
List<String> parts = StringUtils.split( value, ',' ); List<String> parts = StringUtils.split( value, ',' );
@@ -292,13 +301,13 @@ class UIDefaultsLoader
: new FlatEmptyBorder( insets ); : new FlatEmptyBorder( insets );
}; };
} else } else
return parseInstance( value ); return parseInstance( value, addonClassLoaders );
} }
private static Object parseInstance( String value ) { private static Object parseInstance( String value, List<ClassLoader> addonClassLoaders ) {
return (LazyValue) t -> { return (LazyValue) t -> {
try { try {
return Class.forName( value ).newInstance(); return findClass( value, addonClassLoaders ).newInstance();
} catch( InstantiationException | IllegalAccessException | ClassNotFoundException ex ) { } catch( InstantiationException | IllegalAccessException | ClassNotFoundException ex ) {
ex.printStackTrace(); ex.printStackTrace();
return null; return null;
@@ -306,6 +315,35 @@ class UIDefaultsLoader
}; };
} }
private static Object parseClass( String value, List<ClassLoader> addonClassLoaders ) {
return (LazyValue) t -> {
try {
return findClass( value, addonClassLoaders );
} catch( ClassNotFoundException ex ) {
ex.printStackTrace();
return null;
}
};
}
private static Class<?> findClass( String className, List<ClassLoader> addonClassLoaders )
throws ClassNotFoundException
{
try {
return Class.forName( className );
} catch( ClassNotFoundException ex ) {
// search in addons class loaders
for( ClassLoader addonClassLoader : addonClassLoaders ) {
try {
return addonClassLoader.loadClass( className );
} catch( ClassNotFoundException ex2 ) {
// ignore
}
}
throw ex;
}
}
private static Insets parseInsets( String value ) { private static Insets parseInsets( String value ) {
List<String> numbers = StringUtils.split( value, ',' ); List<String> numbers = StringUtils.split( value, ',' );
try { try {