8000 Add class loading to PathAnchor by eiennohito · Pull Request #210 · WorksApplications/Sudachi · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add class loading to PathAnchor #210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions src/main/java/com/worksap/nlp/sudachi/Config.java
8000
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ public class Config {
private List<PluginConf<OovProviderPlugin>> oovProviders;
private List<PluginConf<PathRewritePlugin>> pathRewrite;
private Boolean allowEmptyMorpheme;
private PathAnchor anchor;

private Config() {
private Config(PathAnchor anchor) {
this.anchor = anchor;
}

/**
Expand All @@ -75,7 +77,7 @@ private Config() {
* @return empty Config object
*/
public static Config empty() {
return new Config(); 8000
return new Config(PathAnchor.none());
}

/**
Expand Down Expand Up @@ -289,6 +291,7 @@ private Config fallbackSettings(Settings settings) {
oovProviders = settings.getPlugins("oovProviderPlugin", OovProviderPlugin.class);
pathRewrite = settings.getPlugins("pathRewritePlugin", PathRewritePlugin.class);
allowEmptyMorpheme = settings.getBoolean("allowEmptyMorpheme", null);
anchor = anchor.andThen(settings.base);

return this;
}
Expand Down Expand Up @@ -371,6 +374,7 @@ public Config addUserDictionary(Path path) {
* @param url
* URL of the classpath resource
* @return modified Config
* @see ClassLoader#getResource(String)
*/
public Config addUserDictionary(URL url) {
if (userDictionary == null) {
Expand Down Expand Up @@ -585,6 +589,7 @@ public Config withFallback(Config other) {
oovProviders = mergePluginList(oovProviders, other.oovProviders);
pathRewrite = mergePluginList(pathRewrite, other.pathRewrite);
allowEmptyMorpheme = mergeOne(allowEmptyMorpheme, other.allowEmptyMorpheme);
anchor = anchor.andThen(other.anchor);
return this;
}

Expand All @@ -601,13 +606,36 @@ public boolean equals(Object o) {
&& Objects.equals(editConnectionCost, config.editConnectionCost)
&& Objects.equals(inputText, config.inputText) && Objects.equals(oovProviders, config.oovProviders)
&& Objects.equals(pathRewrite, config.pathRewrite)
&& Objects.equals(allowEmptyMorpheme, config.allowEmptyMorpheme);
&& Objects.equals(allowEmptyMorpheme, config.allowEmptyMorpheme)
&& Objects.equals(anchor, config.anchor);
}

@Override
public int hashCode() {
return Objects.hash(systemDictionary, userDictionary, characterDefinition, editConnectionCost, inputText,
oovProviders, pathRewrite, allowEmptyMorpheme);
oovProviders, pathRewrite, allowEmptyMorpheme, anchor);
}

/**
* Return current {@link PathAnchor} resolver
*
* @return current anchor object
*/
public PathAnchor getAnchor() {
return anchor;
}

/**
* Add the given anchor to the current config object. Passed anchor will be
* resolved last.
*
* @param anchor
* new anchor
* @return updated configuration object
*/
public Config anchoredWith(PathAnchor anchor) {
this.anchor = this.anchor.andThen(anchor);
return this;
}

@FunctionalInterface
Expand Down Expand Up @@ -655,10 +683,11 @@ public static <T extends Plugin> PluginConf<T> make(Class<T> clz) {
* @throws IllegalArgumentException
* when instantiation fails
*/
public T instantiate() {
public T instantiate(PathAnchor anchor) {
Class<? extends T> clz;
PathAnchor realAnchor = anchor.andThen(internal.base);
try {
clz = Class.forName(clazzName).asSubclass(parent);
clz = realAnchor.lookupClass(clazzName).asSubclass(parent);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("non-existent plugin class", e);
}
Expand All @@ -671,7 +700,9 @@ public T instantiate() {
| InvocationTargetException e) {
throw new IllegalArgumentException(e);
}
result.setSettings(internal);
Settings pluginSettings = Settings.empty().withFallback(internal);
pluginSettings.base = realAnchor;
result.setSettings(pluginSettings);
return result;
}

Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/worksap/nlp/sudachi/JapaneseDictionary.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ public class JapaneseDictionary implements Dictionary, DictionaryAccess {
dictionaries = new ArrayList<>();
setupSystemDictionary(config);
for (Config.PluginConf<EditConnectionCostPlugin> p : config.getEditConnectionCostPlugins()) {
EditConnectionCostPlugin instance = p.instantiate();
EditConnectionCostPlugin instance = p.instantiate(config.getAnchor());
instance.setUp(grammar);
instance.edit(grammar);
}
setupCharacterDefinition(config);
inputTextPlugins = new ArrayList<>();
for (Config.PluginConf<InputTextPlugin> p : config.getInputTextPlugins()) {
InputTextPlugin instance = p.instantiate();
InputTextPlugin instance = p.instantiate(config.getAnchor());
instance.setUp(grammar);
inputTextPlugins.add(instance);
}
oovProviderPlugins = new ArrayList<>();
for (Config.PluginConf<OovProviderPlugin> p : config.getOovProviderPlugins()) {
OovProviderPlugin instance = p.instantiate();
OovProviderPlugin instance = p.instantiate(config.getAnchor());
instance.setUp(grammar);
oovProviderPlugins.add(instance);
}
Expand All @@ -65,7 +65,7 @@ public class JapaneseDictionary implements Dictionary, DictionaryAccess {
}
pathRewritePlugins = new ArrayList<>();
for (Config.PluginConf<PathRewritePlugin> p : config.getPathRewritePlugins()) {
PathRewritePlugin instance = p.instantiate();
PathRewritePlugin instance = p.instantiate(config.getAnchor());
instance.setUp(grammar);
pathRewritePlugins.add(instance);
}
Expand Down
38 changes: 35 additions & 3 deletions src/main/java/com/worksap/nlp/sudachi/PathAnchor.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@
* <li>{@link Classpath} which will resolve classpath resources</li>
* </ul>
* Use static methods for their creation.
*
* <p>
* One more utility of this class is to capture multiple classloaders in case of
* complex environment with multiple classloaders (e.g. ElasticSearch plugins).
* </p>
* <p>
* It is also possible to chain anchors using {@link #andThen(PathAnchor)}
* method, which will resolve the first existing path.
Expand Down Expand Up @@ -169,7 +172,7 @@ public boolean exists(Path path) {
* @return resource, encapsulating path, works both for filesystem and classpath
*/
public <T> Config.Resource<T> toResource(Path path) {
if (Files.exists(path)) {
if (this.exists(path)) {
return new Config.Resource.Filesystem<>(path);
}
return new Config.Resource.NotFound<>(path, this);
Expand Down Expand Up @@ -204,6 +207,17 @@ public PathAnchor andThen(PathAnchor other) {
return new Chain(this, other);
}

/**
* Try to load class with the given name.
*
* @param name
* class name
* @return instance of the class or null if class is not found
*/
public Class<?> lookupClass(String name) throws ClassNotFoundException {
return getClass().getClassLoader().loadClass(name);
}

static class Filesystem extends PathAnchor {
private final Path base;

Expand Down Expand Up @@ -278,6 +292,11 @@ public <T> Config.Resource<T> toResource(Path path) {
return new Config.Resource.Classpath<>(resource);
}

@Override
public Class<?> lookupClass(String name) throws ClassNotFoundException {
return loader.loadClass(name);
}

@Override
public boolean equals(Object obj) {
if (obj instanceof Classpath) {
Expand All @@ -294,7 +313,7 @@ public int hashCode() {

@Override
public String toString() {
return "Classpath{" + "prefix=" + prefix + '}';
return "Classpath{prefix=" + prefix + '}';
}
}

Expand Down Expand Up @@ -347,6 +366,19 @@ public <T> Config.Resource<T> toResource(Path path) {
return new Config.Resource.NotFound<>(path, this);
}

@Override
public Class<?> lookupClass(String name) throws ClassNotFoundException {
for (PathAnchor child : children) {
try {
return child.lookupClass(name);
} catch (ClassNotFoundException ignored) {
// do nothing
}
}

throw new ClassNotFoundException(name);
}

@Override
public boolean equals(Object obj) {
if (obj instanceof Chain) {
Expand Down
23 changes: 8 additions & 15 deletions src/main/java/com/worksap/nlp/sudachi/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@
* {@code path} is a reserved key. It prepends an additional filesystem anchor
* to the current list of anchors.
*
*
* @see Config
* @see PathAnchor
*/
Expand Down Expand Up @@ -401,7 +400,7 @@ public List<List<Integer>> getIntListList(String setting) {
/**
* Returns resolved path mapped by the key, or {@code null} if the Settings
* contains no such key. Paths are resolved using {@link PathAnchor}.
*
* <p>
* Strongly prefer using {@link #getResource(String)} over this method, because
* this method can't handle classpath resources.
*
Expand All @@ -424,7 +423,7 @@ public String getPath(String setting) {
/**
* Returns the setting value as the file path, or {@code null} if there is no
* corresponding setting.
*
* <p>
* Strongly prefer using {@link #getResource(String)} over this method, because
* this method can't handle classpath resources.
*
Expand Down Expand Up @@ -561,14 +560,11 @@ <P extends Plugin> List<Config.PluginConf<P>> getPlugins(String name, Class<P> c
/**
* Merge another Settings object with this object, returning a new Settings
* object. Scalar values and arrays of this object will be replaced by values of
* another object.
*
* The current object will not be modified.
*
* another object. <br>
* The current object will not be modified. <br>
* {@link PathAnchor} of the another object will be merged with this one,
* chaining them using {@link PathAnchor#andThen(PathAnchor)} method, using the
* anchor of the passed Settings object before the current anchor.
*
* anchor of the passed Settings object before the current anchor. <br>
* This is advanced API, in most cases Configs should be merged instead.
*
* @param settings
Expand All @@ -584,14 +580,11 @@ public Settings merge(Settings settings) {
/**
* Merge another Settings object with this object, returning a new Settings
* object. Scalar values and arrays of another object will be added to the
* config if they are not present yet.
*
* The current object will not be modified.
*
* config if they are not present yet. <br>
* The current object will not be modified. <br>
* {@link PathAnchor} of the another object will be merged with this one,
* chaining them using {@link PathAnchor#andThen(PathAnchor)} method, using the
* anchor of the passed Settings object after the current anchor.
*
* anchor of the passed Settings object after the current anchor. <br>
* This is advanced API, in most cases Configs should be merged instead.
*
* @param other
Expand Down
24 changes: 22 additions & 2 deletions src/test/java/com/worksap/nlp/sudachi/ConfigTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class ConfigTest {
}]
}""",
PathAnchor.none())
assertFails { cfg.oovProviderPlugins[0].instantiate() }
assertFails { cfg.oovProviderPlugins[0].instantiate(PathAnchor.none()) }
}

@Test
Expand All @@ -111,7 +111,20 @@ class ConfigTest {
}]
}""",
PathAnchor.none())
assertFails { cfg.oovProviderPlugins[0].instantiate() }
assertFails { cfg.oovProviderPlugins[0].instantiate(PathAnchor.none()) }
}

@Test
fun pluginInvalidClassNameWithChainedAnchor() {
val cfg =
Config.fromJsonString(
"""{
"oovProviderPlugin": [{
"class": "java.lang.SSSSSString"
}]
}""",
PathAnchor.classpath(Config::class.java.classLoader))
assertFails { cfg.oovProviderPlugins[0].instantiate(PathAnchor.filesystem("")) }
}

@Test
Expand All @@ -124,4 +137,11 @@ class ConfigTest {
assertNotEquals(c1.hashCode(), c3.hashCode())
assertNotEquals(c1, c3)
}

@Test
fun anchoredWith() {
val cfg = Config.empty()
cfg.anchoredWith(PathAnchor.filesystem("test"))
assertIs<PathAnchor.Chain>(cfg.anchor)
}
}
0