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

Fix AbstractMessageConverter not delegating to ContentTypeResolver when message header is null #29768

Closed
wants to merge 1 commit into from

Conversation

yoshikawaa
Copy link
Contributor

@yoshikawaa yoshikawaa commented Jan 5, 2023

Versions

  • Spring Messaging 6.0.3 / 5.3.24

Problems

DefaultContentTypeResolver#resolve will return defaultMimeType if null is passed as MessageHeaders.

@Override
@Nullable
public MimeType resolve(@Nullable MessageHeaders headers) {
if (headers == null || headers.get(MessageHeaders.CONTENT_TYPE) == null) {
return this.defaultMimeType;
}

However, AbstractMessageConverter#getMimeType does not call the contentTypeResolver if null is passed as MessageHeaders.

@Nullable
protected MimeType getMimeType(@Nullable MessageHeaders headers) {
return (headers != null && this.contentTypeResolver != null ? this.contentTypeResolver.resolve(headers) : null);
}

Because of this, even if DefaultContentTypeResolver#defaultMimeType is set properly, it may be ignored.

I've confirmed this issue with Spring Cloud Stream CompositeMessageConverter.
ApplicationJsonMessageMarshallingConverter (child converter of CompositeMessageConverter) has strictContentTypeMatch=true, so it thinks it's not a supported content type.

Fixes

ContentTypeResolver#resolve accepts null, so MessageConverter should always delegate resolution to it.
Fix AbstractMessageConverter#getMimeType not checking the value of MessageHeaders.

@yoshikawaa yoshikawaa marked this pull request as ready for review January 5, 2023 04:34
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jan 5, 2023
@rstoyanchev rstoyanchev added the in: web Issues in web modules (web, webmvc, webflux, websocket) label Jan 24, 2023
@rstoyanchev rstoyanchev added in: messaging Issues in messaging modules (jms, messaging) and removed in: web Issues in web modules (web, webmvc, webflux, websocket) labels Feb 20, 2023
Copy link
Contributor

@rstoyanchev rstoyanchev left a comment

Choose a reason for hiding this comment

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

It looks like this was changed in f813712#diff-f79ea4f7cb1d3ef331698d7edd1ae7cb7326a8082f34d1c55c97a29865e57d6dL238-R243 with @Nullable related updates. ContentTypeResolver is declared to accept null, and the default implementation does handle it, but after the change it is no longer called with null headers.

The PR looks good to me, unless I'm missing something, @jhoeller?

Aside from that, I'm wondering if this should be done for 6.1 since it is technically a change in behavior. I don't know how common it is to have null headers passed in. /cc @artembilan

@rstoyanchev rstoyanchev added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Feb 21, 2023
@rstoyanchev rstoyanchev added this to the 6.1.0-M1 milestone Feb 21, 2023
@rstoyanchev rstoyanchev self-assigned this Feb 21, 2023
@artembilan
Copy link
Member

Right, Rossen, it is not common to pass a null for header value.
Even all our messaging API does not let do that: as long as we provide a null, that is a signal to remove that header.
See a MessageHeaderAccessor for example:

	/**
	 * Set the value for the given header name.
	 * <p>If the provided value is {@code null}, the header will be removed.
	 */
	public void setHeader(String name, @Nullable Object value) {
		if (isReadOnly(name)) {
			throw new IllegalArgumentException("'" + name + "' header is read-only");
		}
		verifyType(name, value);
		if (value != null) {
			// Modify header if necessary
			if (!ObjectUtils.nullSafeEquals(value, getHeader(name))) {
				this.modified = true;
				this.headers.getRawHeaders().put(name, value);
			}
		}
		else {
			// Remove header if available
			if (this.headers.containsKey(name)) {
				this.modified = true;
				this.headers.getRawHeaders().remove(name);
			}
		}
	}

Perhaps for consistency our MessageHeaders must be fixed respectively - to ignore entries of the input Map which has null values...

@rstoyanchev rstoyanchev modified the milestones: 6.1.0-M1, 6.1.0-M2 Jun 13, 2023
rstoyanchev pushed a commit that referenced this pull request Jun 20, 2023
mdeinum pushed a commit to mdeinum/spring-framework that referenced this pull request Jun 29, 2023
mdeinum pushed a commit to mdeinum/spring-framework that referenced this pull request Jun 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: messaging Issues in messaging modules (jms, messaging) type: bug A general bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants