Skip to content
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

feat: implement dependency injection #87

Merged
merged 102 commits into from
Apr 3, 2021
Merged
Show file tree
Hide file tree
Changes from 99 commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
6ca7a41
started work on DI model
pollend Sep 6, 2020
08e04e9
update annotation scheme
pollend Sep 8, 2020
61f57eb
start work on definition loading
pollend Sep 9, 2020
239f67f
add sterotype helper
pollend Sep 10, 2020
c72bb5b
Basic and naive BeanDefinitionGeneration.
DarkWeird Sep 15, 2020
34ec17d
Merge pull request #1 from DarkWeird/di
pollend Sep 15, 2020
14c87e8
update annotation metadata
pollend Sep 22, 2020
6dd08e9
add annotation metadata
pollend Sep 23, 2020
f728ae1
add start of lifecycle model
pollend Sep 24, 2020
72ac6b6
add lifecycle model
pollend Sep 28, 2020
00b8575
update registry pattern
pollend Sep 29, 2020
727733e
add introspection scheme and dependency scheme
pollend Oct 8, 2020
39d2851
add instance model
pollend Oct 12, 2020
190f653
strater on resolution
pollend Nov 6, 2020
045cc48
started work on context
pollend Nov 15, 2020
39c1e8b
setup object model
pollend Nov 16, 2020
e845739
update instance implementation
pollend Nov 18, 2020
4dac633
update service graph
pollend Nov 22, 2020
e522bc7
update beankey
pollend Nov 23, 2020
55bfc02
fix(gestalt-di): fix NPE at annotations - add DefaultAnnotationValue#…
DarkWeird Nov 30, 2020
35e7079
fix(gestalt-di): fix not accessable class - add public and final modi…
DarkWeird Nov 30, 2020
2ac6674
Merge pull request #2 from DarkWeird/feature/DI
pollend Dec 2, 2020
f746a47
update annotationprocessor
pollend Dec 3, 2020
8498b02
Merge branch 'feature/DI' of github.com:pollend/gestalt into feature/DI
pollend Dec 3, 2020
82a04a2
add beantransation
pollend Dec 7, 2020
20c63da
implement BeanContext
pollend Dec 14, 2020
fcce218
Merge branch 'develop' into feature/DI
DarkWeird Dec 14, 2020
5def158
Convert get beans and resolve to returns `java.util.Optional`
DarkWeird Dec 14, 2020
70770c1
Fix Optional<Optional<T>> returns from resolve.
DarkWeird Dec 15, 2020
6a2a838
chore(gestalt-di): code cleanup, refactor raw-types
DarkWeird Dec 15, 2020
653e252
chore(gestalt-di): refactor raw-types
DarkWeird Dec 15, 2020
56da4a8
remove BeanTransaction
pollend Dec 19, 2020
5354e92
add scanner
pollend Dec 20, 2020
2cdd6ca
implement bean enviroment
pollend Dec 21, 2020
bb6bf5f
clean up BeanEnvironment
pollend Dec 21, 2020
ed8bb31
correct read and write lock
pollend Dec 21, 2020
26f7a93
update test and expanded BeanEnvironment
pollend Dec 24, 2020
0bb14a0
added scanner logic
pollend Dec 25, 2020
ddf7cf2
fix binary search
pollend Dec 25, 2020
4225624
add injection sample
pollend Dec 25, 2020
c641e18
correct bean resolution
pollend Dec 26, 2020
97f72ba
simplify test cases
pollend Dec 26, 2020
a2b5bed
fixed binary search
pollend Dec 26, 2020
20c7ffa
Merge branch 'develop' into feature/DI
pollend Feb 27, 2021
d3b30fe
correct hash calculation and update resolution
pollend Feb 28, 2021
b416bfe
update BeanDefinitionProcessor for nested classes
pollend Feb 28, 2021
eb56666
update test and add better error handeling
pollend Mar 1, 2021
0700f97
correct injection logic
pollend Mar 1, 2021
3aa0a7f
update supplier to inject dependencies
pollend Mar 1, 2021
48e8f97
javadoc: fix Javadoc's tags `tt` -> `@code` because `javadoc` task th…
DarkWeird Mar 2, 2021
887ba86
fix(DestSol): make `gestalt-di` and `gestalt-inject-java` compiles at…
DarkWeird Mar 2, 2021
5a3974b
feature(DI): Implement `javax.inject.Provider` for `Lazy`-like resolu…
DarkWeird Mar 2, 2021
959fd2f
feature(DI): Add possible to search multiple beans via `BeanContext#g…
DarkWeird Mar 2, 2021
40348ad
feature(DI): Add possible to inject `Set`, `List` and `Collection` ty…
DarkWeird Mar 3, 2021
de33483
fix(DI): fix infinity loop at finding beans when context has parent(g…
DarkWeird Mar 3, 2021
9ecea2c
feat: implement bean intercept to intercept request
pollend Mar 6, 2021
05a1a6c
use multimap to drive intercept
pollend Mar 6, 2021
12cc419
add copyright
pollend Mar 7, 2021
f02abc4
start on javadocs
pollend Mar 7, 2021
473a7b5
cleanup
pollend Mar 7, 2021
6278922
Merge remote-tracking branch 'origin/feature/DI' into feature/DI-bean…
DarkWeird Mar 9, 2021
642c08d
Merge pull request #90 from MovingBlocks/feature/DI-bean-intercept
DarkWeird Mar 9, 2021
c5dad5c
update beanDefinitionProcessor to look for annotations for fields and…
pollend Mar 13, 2021
d59e373
feat(gestalt-di): `gestalt-module` not use `reflections` anymore
DarkWeird Mar 12, 2021
90fe84a
feat(gestalt-DI): implements ClassIndex for Classloader with packageP…
DarkWeird Mar 12, 2021
2f07f75
chore(gestalt-DI): javadocs for ClassIndex and cleanup
DarkWeird Mar 12, 2021
337ce07
fix(gestalt-DI): Replaces `Reflections`'s commented code to own metho…
DarkWeird Mar 12, 2021
539eab9
feat(gestalt-DI): Implement `ResourceProcessor`. move ClasspathFileSo…
DarkWeird Mar 12, 2021
ad2cabb
feature(gestalt-DI): Tune ResourceProcessor Logs IOException, works w…
DarkWeird Mar 15, 2021
8b5a408
feature(gestalt-DI): Add resource dir to input of `compileJava`'s - p…
DarkWeird Mar 15, 2021
9395b0c
fix(gestalt-DI): fix classpath resource naming.
DarkWeird Mar 15, 2021
e63b01f
feat(gestalt-DI): add `@Index` to assets-core's annotation and adding…
DarkWeird Mar 15, 2021
a6b3cef
fix(gestalt-DI): add `-` as valid part of filename.
DarkWeird Mar 15, 2021
463b0fc
fix(gestalt-DI): `@Inherited` cannot works with annotation. handle th…
DarkWeird Mar 15, 2021
842f34e
feat(gestalt-DI): fix tests for `entity-system`. provide indexes to `…
DarkWeird Mar 15, 2021
5e95f18
feat(gestalt-DI): Integrate `BeanContext` to `ModuleEnvironment`. Add…
DarkWeird Mar 16, 2021
533475a
feat(gestalt-DI): closing BeanContext when ModuleEnvironment is closing
DarkWeird Mar 16, 2021
f15dcd7
chore(gestalt-DI): uninject PermissionProviderFactories.
DarkWeird Mar 16, 2021
44a2f5c
feat(gestalt-DI): remove non-di `ModuleEnvironment` usage.
DarkWeird Mar 17, 2021
ea1fd1f
Update gestalt-asset-core/src/main/java/org/terasology/gestalt/assets…
DarkWeird Mar 18, 2021
2dde0fe
Merge pull request #91 from MovingBlocks/feature/DI-at-module
DarkWeird Mar 18, 2021
a571932
chore(gestalt-di): fix javadocs, provide gestalt-di via gestalt-modul…
DarkWeird Mar 18, 2021
60dc7cc
replaced introspected with Service and added more docs
pollend Mar 19, 2021
95cb2ff
update javadocs
pollend Mar 19, 2021
267abd1
fix(gestalt-di): fix package with target annotation writing.
DarkWeird Mar 18, 2021
7c94019
fix(gestalt-di): add underscore as valid part of filename
DarkWeird Mar 18, 2021
45519ce
fix(gestalt-di): provide JCIP annotations as api instead implementati…
DarkWeird Mar 19, 2021
88c7971
fix(gestalt-di): `UrlClassIndex#byClassloader*` loads all resources. …
DarkWeird Mar 19, 2021
65ece59
fix(gestalt-di): make type erasure for writing index. fixes index for…
DarkWeird Mar 19, 2021
db49b97
chore: cleanup and organization
pollend Mar 20, 2021
325293f
cleanup argument and add handler for optional
pollend Mar 21, 2021
8003208
Fixed gestalt-inject-java annotation processing errors on Windows.
BenjaminAmos Mar 22, 2021
7ef60d5
Fixed gestalt-android and gestalt-android-testbed compilation.
BenjaminAmos Mar 23, 2021
55d057c
Fixed ResourceProcessor producing incorrect paths on Windows.
BenjaminAmos Mar 23, 2021
a33e8df
Fixed gestalt-android-testbed to work with gestalt-di changes.
BenjaminAmos Mar 27, 2021
c7ab1dd
Merge pull request #93 from BenjaminAmos/gestalt-di-path-fixes
pollend Mar 27, 2021
c09de06
Merge pull request #94 from BenjaminAmos/gestalt-di-android-fixes
pollend Mar 27, 2021
418603e
add annotation test
pollend Mar 27, 2021
821c92a
update annotation value
pollend Mar 27, 2021
7c97ac1
remove reflection and unused test
pollend Mar 31, 2021
0d2c0a7
chore(gestalt-di): handle di's TODOs
DarkWeird Mar 31, 2021
e63977e
chore(gestalt-di): add exception logging instead printStackTrace
DarkWeird Mar 31, 2021
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ Icon
#Ignore Windows
ehthumbs.db
Thumbs.db

gestalt-di/test-modules/
60 changes: 13 additions & 47 deletions gestalt-android-testbed/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,6 @@
* limitations under the License.
*/

import com.google.common.base.Predicate
import org.reflections.Reflections
import org.reflections.scanners.ResourcesScanner
import org.reflections.scanners.SubTypesScanner
import org.reflections.scanners.TypeAnnotationsScanner
import org.reflections.serializers.JsonSerializer
import org.reflections.util.ConfigurationBuilder

import java.util.regex.Pattern

apply plugin: 'com.android.application'
apply plugin: 'project-report'

Expand All @@ -41,24 +31,15 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
packagingOptions {
merge 'META-INF/annotations/*'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just leaving a note here to explain that this merges all the META-INF/annotations files from the jars that are dependencies of gestalt-android-testbed into each other. Android APK files aggregate all dependencies and the main program into a single archive. This might need to be done with META-INF/subtypes in the future but hasn't been needed so-far.

}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
applicationVariants.all {
variant ->
def t = task("reflect${variant.name.capitalize()}") {
description = "Generates reflections manifest for variant ${variant.name}"

doLast {
reflectPackage("org.terasology.gestalt.android.testbed.packageModuleA", variant)
reflectPackage("org.terasology.gestalt.android.testbed.packageModuleB", variant)
}
}
variant.assembleProvider.get().dependsOn(t)
}
lintOptions {
abortOnError false
}
Expand All @@ -78,32 +59,17 @@ dependencies {
testImplementation "junit:junit:$junit_version"
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

annotationProcessor project(":gestalt-inject-java")
}

def reflectPackage(packageName, variant) {
def resourcesPath = variant.sourceSets.find { it.name == 'main' }.resources.srcDirs
def classPath = files { variant.javaCompileProvider.get().destinationDir }
URL[] scanUrls = classPath.collect { it.toURI().toURL() } + resourcesPath.collect {
it.toURI().toURL()
// Android projects don't provide direct access to compileJava but this seems to work.
// https://stackoverflow.com/a/42297051
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
// Adds Resources as parameter for AnnotationProcessor (gather ResourceIndex,
// also add resource as input for compilejava, for re-gathering ResourceIndex, when resource was changed.
inputs.files android.sourceSets.main.resources.srcDirs
options.compilerArgs = ["-Aresource=${android.sourceSets.main.resources.srcDirs.join(File.pathSeparator)}"]
}
URL[] classLoaderUrls = scanUrls + variant.javaCompileProvider.get().classpath.collect {
it.toURI().toURL()
} + [new File(android.sdkDirectory, "platforms/" + android.compileSdkVersion + "/android.jar").toURI().toURL()]

ClassLoader classLoader = new URLClassLoader(classLoaderUrls, getClass().getClassLoader())
org.reflections.Configuration config = new ConfigurationBuilder()
config.addClassLoader(classLoader)
config.setUrls(scanUrls)
config.filterInputsBy(new Predicate<String>() {
@Override
boolean apply(@javax.annotation.Nullable String s) {
return packageName.isEmpty() || s.startsWith(packageName + ".")
}
})

config.addScanners(new ResourcesScanner(), new SubTypesScanner(false), new TypeAnnotationsScanner().filterResultsBy())
Reflections reflections = new Reflections(config)
JsonSerializer serializer = new JsonSerializer()
def outPath = variant.javaCompileProvider.get().destinationDir.toString() + "/" + packageName.replaceAll(Pattern.quote("."), "/") + "/manifest.json"
serializer.save(reflections, outPath)
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@
import org.terasology.gestalt.android.testbed.assettypes.TextData;
import org.terasology.gestalt.android.testbed.assettypes.TextFactory;
import org.terasology.gestalt.android.testbed.assettypes.TextFileFormat;
import org.terasology.gestalt.di.DefaultBeanContext;
import org.terasology.gestalt.module.Module;
import org.terasology.gestalt.module.ModuleEnvironment;
import org.terasology.gestalt.module.ModuleFactory;
import org.terasology.gestalt.module.ModuleMetadata;
import org.terasology.gestalt.module.ModulePathScanner;
import org.terasology.gestalt.module.ModuleServiceRegistry;
import org.terasology.gestalt.module.TableModuleRegistry;
import org.terasology.gestalt.module.resources.FileReference;
import org.terasology.gestalt.module.sandbox.StandardPermissionProviderFactory;
Expand Down Expand Up @@ -93,7 +95,7 @@ protected void onCreate(Bundle savedInstanceState) {
StandardPermissionProviderFactory permissionProviderFactory = new StandardPermissionProviderFactory();
permissionProviderFactory.getBasePermissionSet().addAPIPackage("java.lang");
permissionProviderFactory.getBasePermissionSet().addAPIPackage("org.terasology.test.api");
ModuleEnvironment environment = new ModuleEnvironment(moduleRegistry, new WarnOnlyProviderFactory(permissionProviderFactory), (module, parent, permissionProvider) -> AndroidModuleClassLoader.create(module, parent, permissionProvider, getCodeCacheDir()));
ModuleEnvironment environment = new ModuleEnvironment(new DefaultBeanContext(new ModuleServiceRegistry(permissionProviderFactory)), moduleRegistry, new WarnOnlyProviderFactory(permissionProviderFactory), (module, parent, permissionProvider) -> AndroidModuleClassLoader.create(module, parent, permissionProvider, getCodeCacheDir()));


displayText.append("-== Module Content ==-\n\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@
android:layout_height="match_parent"
tools:context=".GestaltTestActivity">

<TextView
android:id="@+id/textDisplay"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/textDisplay"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Hello World!"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</ScrollView>

</android.support.constraint.ConstraintLayout>
1 change: 1 addition & 0 deletions gestalt-android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ dependencies {
}
implementation project(':gestalt-util')
implementation "org.slf4j:slf4j-api:$slf4j_version"
implementation "com.google.guava:guava:$guava_version"

implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation "junit:junit:$junit_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.context.FindResourcesClassLoader;
import org.terasology.gestalt.module.Module;
import org.terasology.gestalt.module.sandbox.JavaModuleClassLoader;
import org.terasology.gestalt.module.sandbox.ModuleClassLoader;
Expand All @@ -28,15 +29,17 @@
import org.terasology.gestalt.naming.Name;

import java.io.File;
import java.net.URL;
import java.security.AccessController;
import java.util.Enumeration;
import java.util.List;

import dalvik.system.DexClassLoader;

/**
* A module class loader built on top of DexClassLoader, to support loading code under Android.
*/
public class AndroidModuleClassLoader extends DexClassLoader implements ModuleClassLoader {
public class AndroidModuleClassLoader extends DexClassLoader implements ModuleClassLoader, FindResourcesClassLoader {

private static final Logger logger = LoggerFactory.getLogger(JavaModuleClassLoader.class);
private static final Joiner FILE_JOINER = Joiner.on(File.pathSeparatorChar);
Expand Down Expand Up @@ -94,6 +97,11 @@ public PermissionProvider getPermissionProvider() {
return permissionProvider;
}

@Override
public Enumeration<URL> findResources(String name) {
return super.findResources(name);
}

/**
* @return The non-ModuleClassLoader that the module classloader chain is based on
*/
Expand Down
20 changes: 18 additions & 2 deletions gestalt-asset-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,33 @@ apply plugin: 'maven-publish'
dependencies {
implementation project(":gestalt-util")
implementation project(":gestalt-module")
implementation project(":gestalt-inject")
annotationProcessor project(":gestalt-inject-java")


implementation "com.google.guava:guava:$guava_version"
implementation "org.slf4j:slf4j-api:$slf4j_version"
implementation "com.android.support:support-annotations:$android_annotation_version"
implementation "net.jcip:jcip-annotations:$jcip_annotation_version"
api "net.jcip:jcip-annotations:$jcip_annotation_version"

testAnnotationProcessor project(":gestalt-inject-java")
testImplementation "junit:junit:$junit_version"
testImplementation "ch.qos.logback:logback-classic:$logback_version"
testImplementation "org.mockito:mockito-core:$mockito_version"

}


compileJava {
inputs.files sourceSets.main.resources.srcDirs
options.compilerArgs = ["-Aresource=${sourceSets.main.resources.srcDirs.join(File.pathSeparator)}"]
}
compileTestJava {
inputs.files sourceSets.test.resources.srcDirs
options.compilerArgs = ["-Aresource=${sourceSets.test.resources.srcDirs.join(File.pathSeparator)}"]
}


description = 'Provides support for assets - binary resources that can be loaded from modules or procedurally generated at runtime.'

sourceCompatibility = 1.8
Expand Down Expand Up @@ -81,4 +97,4 @@ publishing {
artifact javadocJar
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableSet;

import org.terasology.context.annotation.API;
import org.terasology.gestalt.assets.management.AssetManager;
import org.terasology.gestalt.module.sandbox.API;
import org.terasology.gestalt.naming.Name;

import java.io.IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import net.jcip.annotations.ThreadSafe;

import org.terasology.gestalt.module.sandbox.API;
import org.terasology.context.annotation.API;

import java.util.Optional;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package org.terasology.gestalt.assets;

import org.terasology.gestalt.module.sandbox.API;
import org.terasology.context.annotation.API;

/**
* AssetData is the implementation agnostic data for an asset - typically it isn't dependant on either the source format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package org.terasology.gestalt.assets;

import org.terasology.gestalt.module.sandbox.API;
import org.terasology.context.annotation.API;
import org.terasology.gestalt.naming.Name;

import java.io.IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package org.terasology.gestalt.assets;

import org.terasology.gestalt.module.sandbox.API;
import org.terasology.context.annotation.API;

/**
* AssetFactorys are used to load AssetData into new assets.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.gestalt.module.sandbox.API;
import org.terasology.context.annotation.API;
import org.terasology.gestalt.naming.Name;
import org.terasology.gestalt.util.reflection.GenericsUtil;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;

import org.terasology.context.annotation.API;
import org.terasology.gestalt.assets.exceptions.InvalidUrnException;
import org.terasology.gestalt.module.sandbox.API;
import org.terasology.gestalt.naming.Name;

import java.util.regex.Matcher;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@
@API
package org.terasology.gestalt.assets.exceptions;

import org.terasology.gestalt.module.sandbox.API;
import org.terasology.context.annotation.API;
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@
@API
package org.terasology.gestalt.assets.format;

import org.terasology.gestalt.module.sandbox.API;
import org.terasology.context.annotation.API;
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@

import net.jcip.annotations.ThreadSafe;

import org.terasology.context.annotation.API;
import org.terasology.gestalt.assets.Asset;
import org.terasology.gestalt.assets.AssetData;
import org.terasology.gestalt.assets.AssetType;
import org.terasology.gestalt.assets.ResourceUrn;
import org.terasology.gestalt.module.sandbox.API;
import org.terasology.gestalt.naming.Name;

import java.util.Collections;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,13 @@
package org.terasology.gestalt.assets.management;

import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Multimaps;

import net.jcip.annotations.ThreadSafe;

import org.reflections.ReflectionUtils;
import org.terasology.gestalt.assets.Asset;
import org.terasology.gestalt.assets.AssetData;
import org.terasology.gestalt.assets.AssetFactory;
Expand All @@ -52,6 +48,17 @@ public final class MapAssetTypeManager implements AssetTypeManager {
private final ListMultimap<Class<? extends Asset>, Class<? extends Asset>> subtypes =
Multimaps.synchronizedListMultimap(ArrayListMultimap.<Class<? extends Asset>, Class<? extends Asset>>create());

private static Iterable<Class<?>> getAllSuperClasses(Class<?> from, Class<?> to) {
Preconditions.checkArgument(to.isAssignableFrom(from), "%s should be subtype of %s", from, to);
List<Class<?>> subtypes = Lists.newArrayList();
Class<?> current = from;
while (current != to) {
subtypes.add(current);
current = current.getSuperclass();
}
return subtypes;
}

@Override
@SuppressWarnings("unchecked")
public <T extends Asset<U>, U extends AssetData> Optional<AssetType<T, U>> getAssetType(Class<T> type) {
Expand Down Expand Up @@ -109,7 +116,7 @@ public synchronized void addAssetType(AssetType<?, ?> assetType) {
Preconditions.checkState(assetTypes.get(assetType.getAssetClass()) == null, "Asset type already registered for - " + assetType.getAssetClass().getSimpleName());

assetTypes.put(assetType.getAssetClass(), assetType);
for (Class<?> parentType : ReflectionUtils.getAllSuperTypes(assetType.getAssetClass(), (Predicate<Class<?>>) input -> Asset.class.isAssignableFrom(input) && input != Asset.class)) {
for (Class<?> parentType : getAllSuperClasses(assetType.getAssetClass(), Asset.class)) {
subtypes.put((Class<? extends Asset>) parentType, assetType.getAssetClass());
(subtypes.get((Class<? extends Asset>) parentType)).sort(Comparator.comparing(Class::getSimpleName));

Expand All @@ -128,7 +135,7 @@ public synchronized void addAssetType(AssetType<?, ?> assetType) {
AssetType<?, ?> assetType = assetTypes.remove(type);
if (assetType != null) {
assetType.close();
for (Class<?> parentType : ReflectionUtils.getAllSuperTypes(type, (Predicate<Class<?>>) input -> Asset.class.isAssignableFrom(input) && input != Asset.class)) {
for (Class<?> parentType : getAllSuperClasses(type, Asset.class)) {
subtypes.remove(parentType, type);
}
}
Expand All @@ -145,6 +152,4 @@ public synchronized void clear() {
assetTypes.clear();
subtypes.clear();
}


}
Loading