blob: c7c3b8995385a9e02c0ec85cea09f84973c41192 [file] [log] [blame]
package org.robolectric.config;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;
import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
/**
* Holds configuration objects for the current test, computed using
* {@link org.robolectric.pluginapi.Configurer}.
*
* Configuration is computed before tests run, outside of their sandboxes. If the configuration
* is needed from within a sandbox (when a test is executing), we need to transfer it to a class
* that the SandboxClassLoader recognizes. We do this by serializing and deserializing in
* {@link #reloadInSandboxClassLoader(Object)}.
*/
public class ConfigurationRegistry {
public static ConfigurationRegistry instance;
/**
* Returns the configuration object of the specified class, computed using
* {@link org.robolectric.pluginapi.Configurer}.
*/
public static <T> T get(Class<T> configClass) {
return instance.getInSandboxClassLoader(configClass);
}
private final Map<String, Object> configurations = new HashMap<>();
public ConfigurationRegistry(Configuration configuration) {
for (Class<?> classInParentLoader : configuration.keySet()) {
Object configInParentLoader = configuration.get(classInParentLoader);
configurations.put(classInParentLoader.getName(), configInParentLoader);
}
}
private <T> T getInSandboxClassLoader(Class<T> someConfigClass) {
Object configInParentLoader = configurations.get(someConfigClass.getName());
Object configInSandboxLoader = reloadInSandboxClassLoader(configInParentLoader);
return someConfigClass.cast(configInSandboxLoader);
}
private static Object reloadInSandboxClassLoader(Object configInParentLoader) {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(buf)) {
out.writeObject(configInParentLoader);
} catch (IOException e) {
throw new RuntimeException(e);
}
byte[] bytes = buf.toByteArray();
// ObjectInputStream loads classes in the current classloader by magic
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
return in.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}