Skip to content

Commit 479df9e

Browse files
committed
Fix parsing of UserUpdatedEvents
When I subscribed to UserUpdateEvents, all events are of the type: `EventStreamSubscribeEventsResponseContent._UnknownValue, without readable data. This commit fixes this. Added a EventsSubscribeSseTest wich shows the original problem.
1 parent 93d3100 commit 479df9e

8 files changed

Lines changed: 337 additions & 157 deletions

src/main/java/com/auth0/client/mgmt/AsyncRawEventsClient.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,10 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO
109109
ResponseBody responseBody = response.body();
110110
if (response.isSuccessful()) {
111111
future.complete(new ManagementApiHttpResponse<>(
112-
Stream.fromSse(
112+
Stream.fromSseWithEventDiscrimination(
113113
EventStreamSubscribeEventsResponseContent.class,
114-
new ResponseBodyReader(response)),
114+
new ResponseBodyReader(response),
115+
"type"),
115116
response));
116117
return;
117118
}

src/main/java/com/auth0/client/mgmt/RawEventsClient.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,10 @@ public ManagementApiHttpResponse<Iterable<EventStreamSubscribeEventsResponseCont
100100
ResponseBody responseBody = response.body();
101101
if (response.isSuccessful()) {
102102
return new ManagementApiHttpResponse<>(
103-
Stream.fromSse(
104-
EventStreamSubscribeEventsResponseContent.class, new ResponseBodyReader(response)),
103+
Stream.fromSseWithEventDiscrimination(
104+
EventStreamSubscribeEventsResponseContent.class,
105+
new ResponseBodyReader(response),
106+
"type"),
105107
response);
106108
}
107109
String responseBodyString = responseBody != null ? responseBody.string() : "{}";

src/main/java/com/auth0/client/mgmt/core/SseEventParser.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,44 @@ public static <T> T parseEventLevelUnion(
7474
}
7575
}
7676

77+
/**
78+
* Parse an SSE event whose discriminator is not part of the SSE envelope shape (i.e.
79+
* {@link #isEventLevelDiscrimination(String)} is {@code false}) but is also absent from the
80+
* wire payload itself. Merges the SSE {@code event:} name into the root of the parsed
81+
* {@code data:} object under {@code discriminatorProperty}, without overwriting a
82+
* pre-existing value, then deserializes the merged object to the target type.
83+
*
84+
* @param eventType The SSE event type (from event: field)
85+
* @param data The SSE data content (from data: field)
86+
* @param unionClass The target union class
87+
* @param discriminatorProperty The property name used for discrimination (e.g., "type")
88+
* @param <T> The target type
89+
* @return The deserialized object
90+
*/
91+
public static <T> T parseWithInjectedDiscriminator(
92+
String eventType, String data, Class<T> unionClass, String discriminatorProperty) {
93+
Map<String, Object> parsedData = null;
94+
if (data != null && !data.isEmpty()) {
95+
try {
96+
parsedData = ObjectMappers.JSON_MAPPER.readValue(data, new TypeReference<Map<String, Object>>() {});
97+
} catch (Exception e) {
98+
parsedData = null;
99+
}
100+
}
101+
try {
102+
if (parsedData == null) {
103+
return parseDataLevelUnion(data, unionClass);
104+
}
105+
if (eventType != null) {
106+
parsedData.putIfAbsent(discriminatorProperty, eventType);
107+
}
108+
String mergedJson = ObjectMappers.JSON_MAPPER.writeValueAsString(parsedData);
109+
return ObjectMappers.JSON_MAPPER.readValue(mergedJson, unionClass);
110+
} catch (Exception e) {
111+
throw new RuntimeException("Failed to parse SSE event with injected discriminator", e);
112+
}
113+
}
114+
77115
/**
78116
* Parse an SSE event using data-level discrimination.
79117
* <p>

src/main/java/com/auth0/client/mgmt/core/Stream.java

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -410,14 +410,7 @@ private boolean readNextMessage() {
410410
if (line.trim().isEmpty()) {
411411
if (eventDataBuffer.length() > 0 || currentEventType != null) {
412412
try {
413-
// Use SseEventParser for event-level discrimination
414-
nextItem = SseEventParser.parseEventLevelUnion(
415-
currentEventType,
416-
eventDataBuffer.toString(),
417-
currentEventId,
418-
currentRetry,
419-
valueType,
420-
discriminatorProperty);
413+
nextItem = parseCurrentEvent();
421414
hasNextItem = true;
422415
resetEventState();
423416
return true;
@@ -477,13 +470,7 @@ private boolean readNextMessage() {
477470
// Handle any remaining buffered data at end of stream
478471
if (eventDataBuffer.length() > 0 || currentEventType != null) {
479472
try {
480-
nextItem = SseEventParser.parseEventLevelUnion(
481-
currentEventType,
482-
eventDataBuffer.toString(),
483-
currentEventId,
484-
currentRetry,
485-
valueType,
486-
discriminatorProperty);
473+
nextItem = parseCurrentEvent();
487474
hasNextItem = true;
488475
resetEventState();
489476
return true;
@@ -509,5 +496,15 @@ private void resetEventState() {
509496
currentEventId = null;
510497
currentRetry = null;
511498
}
499+
500+
private T parseCurrentEvent() {
501+
String data = eventDataBuffer.toString();
502+
if (SseEventParser.isEventLevelDiscrimination(discriminatorProperty)) {
503+
return SseEventParser.parseEventLevelUnion(
504+
currentEventType, data, currentEventId, currentRetry, valueType, discriminatorProperty);
505+
}
506+
return SseEventParser.parseWithInjectedDiscriminator(
507+
currentEventType, data, valueType, discriminatorProperty);
508+
}
512509
}
513510
}

src/main/java/com/auth0/client/mgmt/types/EventStreamCloudEventUserCreatedObjectIdentitiesItem.java

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -113,58 +113,56 @@ static final class Deserializer extends StdDeserializer<EventStreamCloudEventUse
113113
public EventStreamCloudEventUserCreatedObjectIdentitiesItem deserialize(
114114
JsonParser p, DeserializationContext context) throws IOException {
115115
Object value = p.readValueAs(Object.class);
116-
if (value instanceof Map<?, ?>
117-
&& ((Map<?, ?>) value).containsKey("connection")
118-
&& ((Map<?, ?>) value).containsKey("user_id")
119-
&& ((Map<?, ?>) value).containsKey("provider")
120-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
121-
try {
122-
return of(ObjectMappers.JSON_MAPPER.convertValue(
123-
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemCustom.class));
124-
} catch (RuntimeException e) {
116+
if (value instanceof Map<?, ?>) {
117+
Map<?, ?> map = (Map<?, ?>) value;
118+
Object providerValue = map.get("provider");
119+
String provider = providerValue == null ? null : providerValue.toString();
120+
boolean isSocial = Boolean.TRUE.equals(map.get("isSocial"));
121+
122+
if (isSocial) {
123+
try {
124+
return of(ObjectMappers.JSON_MAPPER.convertValue(
125+
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemSocial.class));
126+
} catch (RuntimeException e) {
127+
}
125128
}
126-
}
127-
if (value instanceof Map<?, ?>
128-
&& ((Map<?, ?>) value).containsKey("connection")
129-
&& ((Map<?, ?>) value).containsKey("user_id")
130-
&& ((Map<?, ?>) value).containsKey("provider")
131-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
132-
try {
133-
return of(ObjectMappers.JSON_MAPPER.convertValue(
134-
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemDatabase.class));
135-
} catch (RuntimeException e) {
129+
if (provider != null
130+
&& EventStreamCloudEventUserCreatedObjectIdentitiesItemDatabaseProviderEnum.valueOf(provider)
131+
.getEnumValue()
132+
!= EventStreamCloudEventUserCreatedObjectIdentitiesItemDatabaseProviderEnum.Value
133+
.UNKNOWN) {
134+
try {
135+
return of(ObjectMappers.JSON_MAPPER.convertValue(
136+
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemDatabase.class));
137+
} catch (RuntimeException e) {
138+
}
136139
}
137-
}
138-
if (value instanceof Map<?, ?>
139-
&& ((Map<?, ?>) value).containsKey("connection")
140-
&& ((Map<?, ?>) value).containsKey("user_id")
141-
&& ((Map<?, ?>) value).containsKey("provider")
142-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
143-
try {
144-
return of(ObjectMappers.JSON_MAPPER.convertValue(
145-
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemEnterprise.class));
146-
} catch (RuntimeException e) {
140+
if (provider != null
141+
&& EventStreamCloudEventUserCreatedObjectIdentitiesItemPasswordlessProviderEnum.valueOf(
142+
provider)
143+
.getEnumValue()
144+
!= EventStreamCloudEventUserCreatedObjectIdentitiesItemPasswordlessProviderEnum.Value
145+
.UNKNOWN) {
146+
try {
147+
return of(ObjectMappers.JSON_MAPPER.convertValue(
148+
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemPasswordless.class));
149+
} catch (RuntimeException e) {
150+
}
147151
}
148-
}
149-
if (value instanceof Map<?, ?>
150-
&& ((Map<?, ?>) value).containsKey("connection")
151-
&& ((Map<?, ?>) value).containsKey("user_id")
152-
&& ((Map<?, ?>) value).containsKey("provider")
153-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
154-
try {
155-
return of(ObjectMappers.JSON_MAPPER.convertValue(
156-
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemPasswordless.class));
157-
} catch (RuntimeException e) {
152+
if (provider != null
153+
&& EventStreamCloudEventUserCreatedObjectIdentitiesItemEnterpriseProviderEnum.valueOf(provider)
154+
.getEnumValue()
155+
!= EventStreamCloudEventUserCreatedObjectIdentitiesItemEnterpriseProviderEnum.Value
156+
.UNKNOWN) {
157+
try {
158+
return of(ObjectMappers.JSON_MAPPER.convertValue(
159+
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemEnterprise.class));
160+
} catch (RuntimeException e) {
161+
}
158162
}
159-
}
160-
if (value instanceof Map<?, ?>
161-
&& ((Map<?, ?>) value).containsKey("connection")
162-
&& ((Map<?, ?>) value).containsKey("user_id")
163-
&& ((Map<?, ?>) value).containsKey("provider")
164-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
165163
try {
166164
return of(ObjectMappers.JSON_MAPPER.convertValue(
167-
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemSocial.class));
165+
value, EventStreamCloudEventUserCreatedObjectIdentitiesItemCustom.class));
168166
} catch (RuntimeException e) {
169167
}
170168
}

src/main/java/com/auth0/client/mgmt/types/EventStreamCloudEventUserDeletedObjectIdentitiesItem.java

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -113,58 +113,56 @@ static final class Deserializer extends StdDeserializer<EventStreamCloudEventUse
113113
public EventStreamCloudEventUserDeletedObjectIdentitiesItem deserialize(
114114
JsonParser p, DeserializationContext context) throws IOException {
115115
Object value = p.readValueAs(Object.class);
116-
if (value instanceof Map<?, ?>
117-
&& ((Map<?, ?>) value).containsKey("connection")
118-
&& ((Map<?, ?>) value).containsKey("user_id")
119-
&& ((Map<?, ?>) value).containsKey("provider")
120-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
121-
try {
122-
return of(ObjectMappers.JSON_MAPPER.convertValue(
123-
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemCustom.class));
124-
} catch (RuntimeException e) {
116+
if (value instanceof Map<?, ?>) {
117+
Map<?, ?> map = (Map<?, ?>) value;
118+
Object providerValue = map.get("provider");
119+
String provider = providerValue == null ? null : providerValue.toString();
120+
boolean isSocial = Boolean.TRUE.equals(map.get("isSocial"));
121+
122+
if (isSocial) {
123+
try {
124+
return of(ObjectMappers.JSON_MAPPER.convertValue(
125+
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemSocial.class));
126+
} catch (RuntimeException e) {
127+
}
125128
}
126-
}
127-
if (value instanceof Map<?, ?>
128-
&& ((Map<?, ?>) value).containsKey("connection")
129-
&& ((Map<?, ?>) value).containsKey("user_id")
130-
&& ((Map<?, ?>) value).containsKey("provider")
131-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
132-
try {
133-
return of(ObjectMappers.JSON_MAPPER.convertValue(
134-
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemDatabase.class));
135-
} catch (RuntimeException e) {
129+
if (provider != null
130+
&& EventStreamCloudEventUserDeletedObjectIdentitiesItemDatabaseProviderEnum.valueOf(provider)
131+
.getEnumValue()
132+
!= EventStreamCloudEventUserDeletedObjectIdentitiesItemDatabaseProviderEnum.Value
133+
.UNKNOWN) {
134+
try {
135+
return of(ObjectMappers.JSON_MAPPER.convertValue(
136+
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemDatabase.class));
137+
} catch (RuntimeException e) {
138+
}
136139
}
137-
}
138-
if (value instanceof Map<?, ?>
139-
&& ((Map<?, ?>) value).containsKey("connection")
140-
&& ((Map<?, ?>) value).containsKey("user_id")
141-
&& ((Map<?, ?>) value).containsKey("provider")
142-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
143-
try {
144-
return of(ObjectMappers.JSON_MAPPER.convertValue(
145-
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemEnterprise.class));
146-
} catch (RuntimeException e) {
140+
if (provider != null
141+
&& EventStreamCloudEventUserDeletedObjectIdentitiesItemPasswordlessProviderEnum.valueOf(
142+
provider)
143+
.getEnumValue()
144+
!= EventStreamCloudEventUserDeletedObjectIdentitiesItemPasswordlessProviderEnum.Value
145+
.UNKNOWN) {
146+
try {
147+
return of(ObjectMappers.JSON_MAPPER.convertValue(
148+
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemPasswordless.class));
149+
} catch (RuntimeException e) {
150+
}
147151
}
148-
}
149-
if (value instanceof Map<?, ?>
150-
&& ((Map<?, ?>) value).containsKey("connection")
151-
&& ((Map<?, ?>) value).containsKey("user_id")
152-
&& ((Map<?, ?>) value).containsKey("provider")
153-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
154-
try {
155-
return of(ObjectMappers.JSON_MAPPER.convertValue(
156-
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemPasswordless.class));
157-
} catch (RuntimeException e) {
152+
if (provider != null
153+
&& EventStreamCloudEventUserDeletedObjectIdentitiesItemEnterpriseProviderEnum.valueOf(provider)
154+
.getEnumValue()
155+
!= EventStreamCloudEventUserDeletedObjectIdentitiesItemEnterpriseProviderEnum.Value
156+
.UNKNOWN) {
157+
try {
158+
return of(ObjectMappers.JSON_MAPPER.convertValue(
159+
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemEnterprise.class));
160+
} catch (RuntimeException e) {
161+
}
158162
}
159-
}
160-
if (value instanceof Map<?, ?>
161-
&& ((Map<?, ?>) value).containsKey("connection")
162-
&& ((Map<?, ?>) value).containsKey("user_id")
163-
&& ((Map<?, ?>) value).containsKey("provider")
164-
&& ((Map<?, ?>) value).containsKey("isSocial")) {
165163
try {
166164
return of(ObjectMappers.JSON_MAPPER.convertValue(
167-
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemSocial.class));
165+
value, EventStreamCloudEventUserDeletedObjectIdentitiesItemCustom.class));
168166
} catch (RuntimeException e) {
169167
}
170168
}

0 commit comments

Comments
 (0)