Generate struct with field for each api scope

Makes it easier to add new api scopes by generating a struct with a
field for each scope.

Bug: 153443117
Test: m nothing
Change-Id: Iec77a858d2c851d99e56568b89cb30aa3ff2a244
diff --git a/java/sdk_library.go b/java/sdk_library.go
index efee7da..19697c1 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -15,17 +15,18 @@
 package java
 
 import (
-	"android/soong/android"
-
 	"fmt"
 	"path"
 	"path/filepath"
+	"reflect"
 	"sort"
 	"strings"
 	"sync"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
 )
 
 const (
@@ -66,6 +67,9 @@
 	// The name of the api scope, e.g. public, system, test
 	name string
 
+	// The name of the field in the dynamically created structure.
+	fieldName string
+
 	// The tag to use to depend on the stubs library module.
 	stubsTag scopeDependencyTag
 
@@ -93,7 +97,7 @@
 
 // Initialize a scope, creating and adding appropriate dependency tags
 func initApiScope(scope *apiScope) *apiScope {
-	//apiScope := &scope
+	scope.fieldName = proptools.FieldNameForProperty(scope.name)
 	scope.stubsTag = scopeDependencyTag{
 		name:     scope.name + "-stubs",
 		apiScope: scope,
@@ -820,15 +824,6 @@
 	// List of shared java libs, common to all scopes, that this module has
 	// dependencies to
 	Libs []string
-
-	// Properties associated with the public api scope.
-	Public sdkLibraryScopeProperties
-
-	// Properties associated with the system api scope.
-	System sdkLibraryScopeProperties
-
-	// Properties associated with the test api scope.
-	Test sdkLibraryScopeProperties
 }
 
 type sdkLibraryImport struct {
@@ -838,16 +833,59 @@
 
 	properties sdkLibraryImportProperties
 
+	// Map from api scope to the scope specific property structure.
+	scopeProperties map[*apiScope]*sdkLibraryScopeProperties
+
 	commonToSdkLibraryAndImport
 }
 
 var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
 
+// The type of a structure that contains a field of type sdkLibraryScopeProperties
+// for each apiscope in allApiScopes, e.g. something like:
+// struct {
+//   Public sdkLibraryScopeProperties
+//   System sdkLibraryScopeProperties
+//   ...
+// }
+var allScopeStructType = createAllScopePropertiesStructType()
+
+// Dynamically create a structure type for each apiscope in allApiScopes.
+func createAllScopePropertiesStructType() reflect.Type {
+	var fields []reflect.StructField
+	for _, apiScope := range allApiScopes {
+		field := reflect.StructField{
+			Name: apiScope.fieldName,
+			Type: reflect.TypeOf(sdkLibraryScopeProperties{}),
+		}
+		fields = append(fields, field)
+	}
+
+	return reflect.StructOf(fields)
+}
+
+// Create an instance of the scope specific structure type and return a map
+// from apiscope to a pointer to each scope specific field.
+func createPropertiesInstance() (interface{}, map[*apiScope]*sdkLibraryScopeProperties) {
+	allScopePropertiesPtr := reflect.New(allScopeStructType)
+	allScopePropertiesStruct := allScopePropertiesPtr.Elem()
+	scopeProperties := make(map[*apiScope]*sdkLibraryScopeProperties)
+
+	for _, apiScope := range allApiScopes {
+		field := allScopePropertiesStruct.FieldByName(apiScope.fieldName)
+		scopeProperties[apiScope] = field.Addr().Interface().(*sdkLibraryScopeProperties)
+	}
+
+	return allScopePropertiesPtr.Interface(), scopeProperties
+}
+
 // java_sdk_library_import imports a prebuilt java_sdk_library.
 func sdkLibraryImportFactory() android.Module {
 	module := &sdkLibraryImport{}
 
-	module.AddProperties(&module.properties)
+	allScopeProperties, scopeToProperties := createPropertiesInstance()
+	module.scopeProperties = scopeToProperties
+	module.AddProperties(&module.properties, allScopeProperties)
 
 	android.InitPrebuiltModule(module, &[]string{""})
 	InitJavaModule(module, android.HostAndDeviceSupported)
@@ -871,7 +909,7 @@
 		module.prebuilt.ForcePrefer()
 	}
 
-	for apiScope, scopeProperties := range module.scopeProperties() {
+	for apiScope, scopeProperties := range module.scopeProperties {
 		if len(scopeProperties.Jars) == 0 {
 			continue
 		}
@@ -921,16 +959,8 @@
 	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
 }
 
-func (module *sdkLibraryImport) scopeProperties() map[*apiScope]*sdkLibraryScopeProperties {
-	p := make(map[*apiScope]*sdkLibraryScopeProperties)
-	p[apiScopePublic] = &module.properties.Public
-	p[apiScopeSystem] = &module.properties.System
-	p[apiScopeTest] = &module.properties.Test
-	return p
-}
-
 func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
-	for apiScope, scopeProperties := range module.scopeProperties() {
+	for apiScope, scopeProperties := range module.scopeProperties {
 		if len(scopeProperties.Jars) == 0 {
 			continue
 		}