Skip to content

Commit cf82353

Browse files
authored
feat: Add nooargs constructors so we work in Jakarta (a2aproject#580)
1 parent 0e7cd52 commit cf82353

File tree

7 files changed

+108
-18
lines changed

7 files changed

+108
-18
lines changed

extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedQueueManager.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,26 @@
2424
public class ReplicatedQueueManager implements QueueManager {
2525
private static final Logger LOGGER = LoggerFactory.getLogger(ReplicatedQueueManager.class);
2626

27-
private final InMemoryQueueManager delegate;
28-
27+
// Fields set by constructor injection cannot be final. We need a noargs constructor for
28+
// Jakarta compatibility, and it seems that making fields set by constructor injection
29+
// final, is not proxyable in all runtimes
30+
private InMemoryQueueManager delegate;
2931
private ReplicationStrategy replicationStrategy;
30-
3132
private TaskStateProvider taskStateProvider;
3233

34+
/**
35+
* No-args constructor for CDI proxy creation.
36+
* CDI requires a non-private constructor to create proxies for @ApplicationScoped beans.
37+
* All fields are initialized by the @Inject constructor during actual bean creation.
38+
*/
39+
@SuppressWarnings("NullAway")
40+
protected ReplicatedQueueManager() {
41+
// For CDI proxy creation
42+
this.delegate = null;
43+
this.replicationStrategy = null;
44+
this.taskStateProvider = null;
45+
}
46+
3347
@Inject
3448
public ReplicatedQueueManager(ReplicationStrategy replicationStrategy, TaskStateProvider taskStateProvider) {
3549
this.replicationStrategy = replicationStrategy;

server-common/src/main/java/io/a2a/server/events/InMemoryQueueManager.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,23 @@ public class InMemoryQueueManager implements QueueManager {
1616
private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryQueueManager.class);
1717

1818
private final ConcurrentMap<String, EventQueue> queues = new ConcurrentHashMap<>();
19-
private final EventQueueFactory factory;
20-
private final TaskStateProvider taskStateProvider;
19+
// Fields set by constructor injection cannot be final. We need a noargs constructor for
20+
// Jakarta compatibility, and it seems that making fields set by constructor injection
21+
// final, is not proxyable in all runtimes
22+
private EventQueueFactory factory;
23+
private TaskStateProvider taskStateProvider;
24+
25+
/**
26+
* No-args constructor for CDI proxy creation.
27+
* CDI requires a non-private constructor to create proxies for @ApplicationScoped beans.
28+
* All fields are initialized by the @Inject constructor during actual bean creation.
29+
*/
30+
@SuppressWarnings("NullAway")
31+
protected InMemoryQueueManager() {
32+
// For CDI proxy creation
33+
this.factory = null;
34+
this.taskStateProvider = null;
35+
}
2136

2237
@Inject
2338
public InMemoryQueueManager(TaskStateProvider taskStateProvider) {

server-common/src/main/java/io/a2a/server/requesthandlers/DefaultRequestHandler.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
import io.a2a.spec.Message;
5757
import io.a2a.spec.MessageSendParams;
5858
import io.a2a.spec.PushNotificationConfig;
59-
import io.a2a.spec.PushNotificationNotSupportedError;
6059
import io.a2a.spec.StreamingEventKind;
6160
import io.a2a.spec.Task;
6261
import io.a2a.spec.TaskIdParams;
@@ -208,17 +207,37 @@ public class DefaultRequestHandler implements RequestHandler {
208207
*/
209208
int consumptionCompletionTimeoutSeconds;
210209

211-
private final AgentExecutor agentExecutor;
212-
private final TaskStore taskStore;
213-
private final QueueManager queueManager;
214-
private final PushNotificationConfigStore pushConfigStore;
215-
private final PushNotificationSender pushSender;
216-
private final Supplier<RequestContext.Builder> requestContextBuilder;
210+
// Fields set by constructor injection cannot be final. We need a noargs constructor for
211+
// Jakarta compatibility, and it seems that making fields set by constructor injection
212+
// final, is not proxyable in all runtimes
213+
private AgentExecutor agentExecutor;
214+
private TaskStore taskStore;
215+
private QueueManager queueManager;
216+
private PushNotificationConfigStore pushConfigStore;
217+
private PushNotificationSender pushSender;
218+
private Supplier<RequestContext.Builder> requestContextBuilder;
217219

218220
private final ConcurrentMap<String, CompletableFuture<Void>> runningAgents = new ConcurrentHashMap<>();
219221
private final Set<CompletableFuture<Void>> backgroundTasks = ConcurrentHashMap.newKeySet();
220222

221-
private final Executor executor;
223+
private Executor executor;
224+
225+
/**
226+
* No-args constructor for CDI proxy creation.
227+
* CDI requires a non-private constructor to create proxies for @ApplicationScoped beans.
228+
* All fields are initialized by the @Inject constructor during actual bean creation.
229+
*/
230+
@SuppressWarnings("NullAway")
231+
protected DefaultRequestHandler() {
232+
// For CDI proxy creation
233+
this.agentExecutor = null;
234+
this.taskStore = null;
235+
this.queueManager = null;
236+
this.pushConfigStore = null;
237+
this.pushSender = null;
238+
this.requestContextBuilder = null;
239+
this.executor = null;
240+
}
222241

223242
@Inject
224243
public DefaultRequestHandler(AgentExecutor agentExecutor, TaskStore taskStore,

server-common/src/main/java/io/a2a/server/tasks/BasePushNotificationSender.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,24 @@ public class BasePushNotificationSender implements PushNotificationSender {
2727

2828
private static final Logger LOGGER = LoggerFactory.getLogger(BasePushNotificationSender.class);
2929

30-
private final A2AHttpClient httpClient;
31-
private final PushNotificationConfigStore configStore;
30+
// Fields set by constructor injection cannot be final. We need a noargs constructor for
31+
// Jakarta compatibility, and it seems that making fields set by constructor injection
32+
// final, is not proxyable in all runtimes
33+
private A2AHttpClient httpClient;
34+
private PushNotificationConfigStore configStore;
35+
36+
37+
/**
38+
* No-args constructor for CDI proxy creation.
39+
* CDI requires a non-private constructor to create proxies for @ApplicationScoped beans.
40+
* All fields are initialized by the @Inject constructor during actual bean creation.
41+
*/
42+
@SuppressWarnings("NullAway")
43+
protected BasePushNotificationSender() {
44+
// For CDI proxy creation
45+
this.httpClient = null;
46+
this.configStore = null;
47+
}
3248

3349
@Inject
3450
public BasePushNotificationSender(PushNotificationConfigStore configStore) {

transport/grpc/src/main/java/io/a2a/transport/grpc/handler/GrpcHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public abstract class GrpcHandler extends A2AServiceGrpc.A2AServiceImplBase {
6767
// Without this we get intermittent failures
6868
private static volatile Runnable streamingSubscribedRunnable;
6969

70-
private AtomicBoolean initialised = new AtomicBoolean(false);
70+
private final AtomicBoolean initialised = new AtomicBoolean(false);
7171

7272
private static final Logger LOGGER = Logger.getLogger(GrpcHandler.class.getName());
7373

transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/handler/JSONRPCHandler.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,27 @@
6060
@ApplicationScoped
6161
public class JSONRPCHandler {
6262

63+
// Fields set by constructor injection cannot be final. We need a noargs constructor for
64+
// Jakarta compatibility, and it seems that making fields set by constructor injection
65+
// final, is not proxyable in all runtimes
6366
private AgentCard agentCard;
6467
private @Nullable Instance<AgentCard> extendedAgentCard;
6568
private RequestHandler requestHandler;
66-
private final Executor executor;
69+
private Executor executor;
70+
71+
/**
72+
* No-args constructor for CDI proxy creation.
73+
* CDI requires a non-private constructor to create proxies for @ApplicationScoped beans.
74+
* All fields are initialized by the @Inject constructor during actual bean creation.
75+
*/
76+
@SuppressWarnings("NullAway")
77+
protected JSONRPCHandler() {
78+
// For CDI proxy creation
79+
this.agentCard = null;
80+
this.extendedAgentCard = null;
81+
this.requestHandler = null;
82+
this.executor = null;
83+
}
6784

6885
@Inject
6986
public JSONRPCHandler(@PublicAgentCard AgentCard agentCard, @Nullable @ExtendedAgentCard Instance<AgentCard> extendedAgentCard,

transport/rest/src/main/java/io/a2a/transport/rest/handler/RestHandler.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,20 @@
6767
public class RestHandler {
6868

6969
private static final Logger log = Logger.getLogger(RestHandler.class.getName());
70+
71+
// Fields set by constructor injection cannot be final. We need a noargs constructor for
72+
// Jakarta compatibility, and it seems that making fields set by constructor injection
73+
// final, is not proxyable in all runtimes
7074
private AgentCard agentCard;
7175
private @Nullable Instance<AgentCard> extendedAgentCard;
7276
private RequestHandler requestHandler;
73-
private final Executor executor;
77+
private Executor executor;
7478

79+
/**
80+
* No-args constructor for CDI proxy creation.
81+
* CDI requires a non-private constructor to create proxies for @ApplicationScoped beans.
82+
* All fields are initialized by the @Inject constructor during actual bean creation.
83+
*/
7584
@SuppressWarnings("NullAway")
7685
protected RestHandler() {
7786
// For CDI

0 commit comments

Comments
 (0)