Skip to content

Fix null EventProperties.getType() on Android (initialize eventType)#1483

Open
bmehta001 wants to merge 3 commits into
microsoft:mainfrom
bmehta001:bhamehta/fix-1329-eventtype-npe
Open

Fix null EventProperties.getType() on Android (initialize eventType)#1483
bmehta001 wants to merge 3 commits into
microsoft:mainfrom
bmehta001:bhamehta/fix-1329-eventtype-npe

Conversation

@bmehta001

Copy link
Copy Markdown
Contributor

What

Initialize EventPropertiesStorage.eventType to "" so EventProperties.getType() returns its documented empty-string default instead of null on a freshly constructed object.

Why

Per #1329, on Android/Java:

EventProperties props = new EventProperties("MyEvent", DiagnosticLevel.DIAG_LEVEL_OPTIONAL);
String type = props.getType(); // was null -> NullPointerException for callers

EventPropertiesStorage()'s default constructor initialized every member (eventName, eventLatency, eventPersistence, …) except eventType, leaving it null. But getType()'s contract (its Javadoc) states "An empty string is returned if this was never set." So the implementation violated its own contract.

Fix

  • EventPropertiesStorage() — initialize eventType = "" (right after eventName = "", matching the existing pattern).
  • EventsUnitTest — add newEventPropertiesGetTypeReturnsEmptyString, asserting getType() on a new EventProperties is non-null and equal to "".

The copy constructor already propagates eventType, and since all default-constructed storages now set "", copies are "" too.

Validation

The change is a one-line field initialization plus a JUnit regression test using already-imported assertions and the pure-Java EventProperties(String, DiagnosticLevel) constructor. I couldn't run gradlew maesdk:test locally (no JDK/Android toolchain on this dev box), so it relies on the Android CI (Build for Android workflow runs maesdk:test) for the build+test confirmation.

Resolves #1329.

…ype()

EventPropertiesStorage's default constructor initialized every member
except eventType, so EventProperties.getType() returned null on a freshly
constructed object instead of its documented empty-string default (microsoft#1329).
On Android/Java this surfaced as a NullPointerException for callers.

- EventPropertiesStorage(): initialize eventType = "" (matching eventName
  and the other members).
- EventsUnitTest: add newEventPropertiesGetTypeReturnsEmptyString as a
  regression test (getType() on a new EventProperties is non-null and "").

Resolves microsoft#1329.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bmehta001 bmehta001 requested a review from a team as a code owner June 12, 2026 13:59
@bmehta001

Copy link
Copy Markdown
Contributor Author

Validated locally on a plain JVM (JDK 17, WSL) by compiling the actual EventProperties / EventPropertiesStorage sources — stubbing only the androidx.annotation.Keep marker and the two JNI-native validators (Utils.validateEventName/validatePropertyName), which are unrelated to this change:

With the fix:

EventPropertiesStorage.eventType => ""
EventProperties.getType()       => ""
RESULT: PASS

Negative control (remove the eventType = ""; line):

EventPropertiesStorage.eventType => null
EventProperties.getType()       => null
RESULT: FAIL

So the one-line initialization is precisely what makes getType() return its documented empty string instead of null.

Note: the earlier Build for Android CI failure here was unrelated to the change — it failed in the actions/setup-java@v5 Setup Java step (transient resolution of the deprecated adopt distribution), before any code was compiled. I've re-run that job. (Switching that workflow's distribution: adopttemurin would remove this fragility — happy to do that as a separate change.)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an Android/Java contract violation where EventProperties.getType() could return null for newly constructed objects, despite its Javadoc specifying an empty-string default. It does so by initializing the underlying storage field and adding a regression test to prevent reintroduction.

Changes:

  • Initialize EventPropertiesStorage.eventType to "" in the default constructor to avoid null returns from getType().
  • Add a JUnit regression test ensuring EventProperties.getType() is non-null and equals "" immediately after construction.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
lib/android_build/maesdk/src/main/java/com/microsoft/applications/events/EventPropertiesStorage.java Initializes eventType to an empty string to match EventProperties.getType()’s documented default behavior.
lib/android_build/maesdk/src/test/java/com/microsoft/applications/events/EventsUnitTest.java Adds a regression test validating getType() returns "" (not null) on a freshly constructed EventProperties.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Code review of the microsoft#1329 fix found a native-path regression. Making Java
getType() return "" (instead of null) fixes the Java-side NPE, but the JNI
converter forwarded the type to native whenever the jstring was non-null:

    if (jstrEventType != NULL)
        eventProperties.SetType(JStringToStdString(env, jstrEventType));

Before microsoft#1329, getType() returned null for a default EventProperties, so
SetType was skipped and native eventType stayed at its "" default. Now the
non-null "" reaches native SetType(""), which fails validateEventName (length
< 4) and, for EVERY typeless event, logs "Invalid event type!" and broadcasts
an EVT_REJECTED DebugEvent to all registered listeners (EventProperties.cpp
SetType -> ILManager::DispatchEventBroadcast) -- a false-positive rejection
signal indistinguishable from a genuinely rejected event.

Fix: in the JNI converter (the sole native SetType chokepoint), treat an empty
type as "unset" and only call SetType for a non-empty string, restoring the
pre-microsoft#1329 native behavior while keeping the corrected Java API contract.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment on lines +395 to +402
// Regression test for #1329: getType() on a freshly constructed
// EventProperties must return its documented default of "" (an empty
// string), not null -- EventPropertiesStorage previously left eventType
// uninitialized.
EventProperties props = new EventProperties("MyEvent", DiagnosticLevel.DIAG_LEVEL_OPTIONAL);
assertNotNull(props.getType());
assertEquals("", props.getType());
}
…ly (no native)

The regression test constructed EventProperties, whose constructor calls
setName() -> native Utils.validateEventName(). These are JVM unit tests
(@RunWith(MockitoJUnitRunner)) with no native library loaded, so it would throw
UnsatisfiedLinkError instead of exercising the regression. Test the pure-Java
EventPropertiesStorage (same package) directly -- the exact class the microsoft#1329 fix
initialized (eventType = "").

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Calling getType() on a new EventProperties object hits a NullPointerException

2 participants