Show one Address component per address so the pane stays in step with the person's list.
A second component of the same class is a new injected instance, leaving the cached singleton in place, and selection stays an attribute of the person. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -67,11 +67,7 @@ public class ApplicationContext {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getComponent(Class<? extends T> type) {
|
||||
ComponentData data = components.get(type);
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("No component found for type: " + type.getName());
|
||||
}
|
||||
|
||||
ComponentData data = componentData(type);
|
||||
Scope scope = data.getScope();
|
||||
Object instance = data.getInstance();
|
||||
|
||||
@@ -79,10 +75,60 @@ public class ApplicationContext {
|
||||
return (T) instance;
|
||||
}
|
||||
|
||||
instance = createInjected(data);
|
||||
if (scope == Scope.SINGLETON) {
|
||||
data.setInstance(instance);
|
||||
}
|
||||
return (T) instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new injected instance without replacing a cached singleton.
|
||||
* <p>
|
||||
* Dependencies of the new instance are the objects {@link #getComponent} returns, so a
|
||||
* singleton dependency is still shared. The new instance itself is not stored as the
|
||||
* singleton for {@code type}.
|
||||
*
|
||||
* @param <T> the type of the component to create
|
||||
* @param type the {@code Class} object representing the type of the component
|
||||
* @return a new instance of the requested component type
|
||||
* @throws IllegalArgumentException if no component is found for the specified type
|
||||
* @throws IllegalStateException if no suitable constructor is found for the component
|
||||
* @throws RuntimeException if any error occurs during instantiation
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T createComponent(Class<? extends T> type) {
|
||||
return (T) createInjected(componentData(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scanned data for a component type.
|
||||
*
|
||||
* @param type the component type
|
||||
* @return the component data
|
||||
* @throws IllegalArgumentException if no component is found for the specified type
|
||||
*/
|
||||
private ComponentData componentData(Class<?> type) {
|
||||
ComponentData data = components.get(type);
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("No component found for type: " + type.getName());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a component and injects its dependencies.
|
||||
* <p>
|
||||
* The instance is not stored. {@link #getComponent} decides whether a singleton caches it.
|
||||
*
|
||||
* @param data the component to construct
|
||||
* @return the new instance
|
||||
*/
|
||||
private Object createInjected(ComponentData data) {
|
||||
try {
|
||||
Constructor<?> injectionConstructor = data.getInjectionConstructor();
|
||||
if (injectionConstructor == null) {
|
||||
throw new IllegalStateException("No injection constructor resolved for " + type.getName());
|
||||
throw new IllegalStateException("No injection constructor resolved for " + data.getType().getName());
|
||||
}
|
||||
|
||||
Class<?>[] paramTypes = injectionConstructor.getParameterTypes();
|
||||
@@ -91,7 +137,7 @@ public class ApplicationContext {
|
||||
parameters[i] = getComponent(paramTypes[i]);
|
||||
}
|
||||
|
||||
instance = injectionConstructor.newInstance(parameters);
|
||||
Object instance = injectionConstructor.newInstance(parameters);
|
||||
|
||||
for (Field field : data.getInjectableFields()) {
|
||||
field.setAccessible(true);
|
||||
@@ -104,12 +150,9 @@ public class ApplicationContext {
|
||||
setter.invoke(instance, getComponent(dependencyType));
|
||||
}
|
||||
|
||||
if (scope == Scope.SINGLETON) {
|
||||
data.setInstance(instance);
|
||||
}
|
||||
return (T) instance;
|
||||
return instance;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Fehler beim Erstellen der Instanz für " + type.getName(), e);
|
||||
throw new RuntimeException("Fehler beim Erstellen der Instanz für " + data.getType().getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
|
||||
class ApplicationContextInjectionTest {
|
||||
@@ -46,5 +47,29 @@ class ApplicationContextInjectionTest {
|
||||
assertSame(rootDependency, service.getFieldInjectedService().getRootDependency());
|
||||
assertSame(rootDependency, service.getSetterInjectedService().getRootDependency());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createComponentInjectsANewInstanceAndKeepsTheSingleton() {
|
||||
MixedInjectionService singleton = context.getComponent(MixedInjectionService.class);
|
||||
MixedInjectionService created = context.createComponent(MixedInjectionService.class);
|
||||
RootDependency root = context.getComponent(RootDependency.class);
|
||||
assertNotSame(singleton, created);
|
||||
assertSame(singleton, context.getComponent(MixedInjectionService.class));
|
||||
assertSame(root, created.getConstructorInjectedService().getRootDependency());
|
||||
assertSame(root, created.getFieldInjectedService().getRootDependency());
|
||||
assertSame(root, created.getSetterInjectedService().getRootDependency());
|
||||
assertSame(singleton.getConstructorInjectedService(), created.getConstructorInjectedService());
|
||||
assertSame(singleton.getFieldInjectedService(), created.getFieldInjectedService());
|
||||
assertSame(singleton.getSetterInjectedService(), created.getSetterInjectedService());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createComponentDoesNotBecomeTheSingleton() {
|
||||
MixedInjectionService created = context.createComponent(MixedInjectionService.class);
|
||||
MixedInjectionService singleton = context.getComponent(MixedInjectionService.class);
|
||||
assertNotSame(created, singleton);
|
||||
assertSame(singleton, context.getComponent(MixedInjectionService.class));
|
||||
assertSame(created.getConstructorInjectedService(), singleton.getConstructorInjectedService());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user