Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LinkedCaseInsensitiveMap#getOrDefault should return default value instead of null #33134

Conversation

poying9464
Copy link

This method directly calls the LinkedHashMap # get of the parent class,
but after obtaining the value, it does not determine whether it is a null value

This method directly calls the LinkedHashMap # get of the parent class,
but after obtaining the value, it does not determine whether it is a null value
@pivotal-cla
Copy link

@poying9464 Please sign the Contributor License Agreement!

Click here to manually synchronize the status of this Pull Request.

See the FAQ for frequently asked questions.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 2, 2024
@pivotal-cla
Copy link

@poying9464 Thank you for signing the Contributor License Agreement!

@ngocnhan-tran1996
Copy link
Contributor

@poying9464

Method getOrDefault was described

Returns:
the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key

More detail Interface Map

LinkedCaseInsensitiveMap<V> implements Map<String, V>, so the value return null belongs one of case

  1. this map does not contains the input key
  2. this input key has null value

I don't think this is a bug but I also wait for confirming from Spring team

@sdeleuze sdeleuze self-assigned this Jul 3, 2024
@sdeleuze sdeleuze added the in: data Issues in data modules (jdbc, orm, oxm, tx) label Jul 3, 2024
@sdeleuze
Copy link
Contributor

sdeleuze commented Jul 3, 2024

The method getOrDefault(Object key, V defaultValue) is annotated with @Nullable, so the behavior currently implemented is likely the right one, so I will decline this PR.

@sdeleuze sdeleuze closed this Jul 3, 2024
@sdeleuze sdeleuze added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jul 3, 2024
@sbrannen
Copy link
Member

sbrannen commented Jul 3, 2024

I took a look at this as well, and I think there's actually a bug in the implementation.

Specifically, I believe LinkedCaseInsensitiveMap.getOrDefault(Object, V) should delegate to LinkedHashMap.getOrDefault(Object, V) as follows.

	public V getOrDefault(Object key, V defaultValue) {
		if (key instanceof String string) {
			String caseInsensitiveKey = this.caseInsensitiveKeys.get(convertKey(string));
			if (caseInsensitiveKey != null) {
				return this.targetMap.getOrDefault(caseInsensitiveKey, defaultValue);
			}
		}
		return defaultValue;
	}

@sdeleuze, what do you think?

@sbrannen sbrannen reopened this Jul 3, 2024
@sbrannen sbrannen added status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team in: core Issues in core modules (aop, beans, core, context, expression) and removed status: declined A suggestion or change that we don't feel we should currently apply in: data Issues in data modules (jdbc, orm, oxm, tx) labels Jul 3, 2024
@sbrannen sbrannen changed the title fix(spring-jdbc):getOrDefault will return a null value LinkedCaseInsensitiveMap#getOrDefault should return default value instead of null Jul 3, 2024
@sbrannen sbrannen added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team labels Jul 3, 2024
@sbrannen
Copy link
Member

sbrannen commented Jul 3, 2024

I took a look at this as well, and I think there's actually a bug in the implementation.

I took a closer look and realized that the if (caseInsensitiveKey != null) effectively already performs the "contains key" logic in this.targetMap.getOrDefault(...).

Thus, there is no need to invoke this.targetMap.getOrDefault(...) or perform any special handling as proposed in this PR.

@poying9464, please note that we have tests in org.springframework.util.LinkedCaseInsensitiveMapTests which verify the expected behavior.

In light of the above, I am re-closing this issue as @sdeleuze had originally.

@sbrannen sbrannen closed this Jul 3, 2024
@poying9464
Copy link
Author

poying9464 commented Jul 3, 2024

The method getOrDefault(Object key, V defaultValue) is annotated with @Nullable, so the behavior currently implemented is likely the right one, so I will decline this PR.

Although this method has the @Nullable annotation, I think that when the return result is null, the given defaultValue should be returned. It should be implemented according to the original design intention of Map#getOrDefault

@sbrannen
Copy link
Member

sbrannen commented Jul 3, 2024

Hi @poying9464,

It should be implemented according to the original design intention of Map#getOrDefault

As I mentioned above, it is already implemented according to the contract of Map#getOrDefault.

See the following tests for details.

@Test
void getOrDefault() {
assertThat(map.put("key", "value1")).isNull();
assertThat(map.put("KEY", "value2")).isEqualTo("value1");
assertThat(map.put("Key", "value3")).isEqualTo("value2");
assertThat(map.getOrDefault("key", "N")).isEqualTo("value3");
assertThat(map.getOrDefault("KEY", "N")).isEqualTo("value3");
assertThat(map.getOrDefault("Key", "N")).isEqualTo("value3");
assertThat(map.getOrDefault("keeeey", "N")).isEqualTo("N");
assertThat(map.getOrDefault(new Object(), "N")).isEqualTo("N");
}
@Test
void getOrDefaultWithNullValue() {
assertThat(map.put("key", null)).isNull();
assertThat(map.put("KEY", null)).isNull();
assertThat(map.put("Key", null)).isNull();
assertThat(map.getOrDefault("key", "N")).isNull();
assertThat(map.getOrDefault("KEY", "N")).isNull();
assertThat(map.getOrDefault("Key", "N")).isNull();
assertThat(map.getOrDefault("keeeey", "N")).isEqualTo("N");
assertThat(map.getOrDefault(new Object(), "N")).isEqualTo("N");
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: declined A suggestion or change that we don't feel we should currently apply
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants