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

Code completion for target with generic builder not working #78

Closed
thunderhook opened this issue Aug 4, 2021 · 2 comments · Fixed by #79
Closed

Code completion for target with generic builder not working #78

thunderhook opened this issue Aug 4, 2021 · 2 comments · Fixed by #79
Labels
Milestone

Comments

@thunderhook
Copy link
Contributor

First of all, thank your awesome work!

We use some generated classes as target and sadly the code completion won't work.
I have reproduced and trimmed the generated class, so that the problem can be reproduced.
Note the comments inside the class to get the completion working (to find the culprit).

Thanks in advance. Please tell me when I can provide further help.

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper
public abstract class DemoMapper {

	// code completion for target broken - see comments down below to see the culprit
	@Mapping(target = "status", source = "input")
	public abstract DemoTypeWithBuilder map(String input);

	public static class DemoTypeWithBuilder {

		protected String status;
		protected int data;

		public String getStatus() {return status;}

		public void setStatus(String value) {this.status = value;}

		public int getData() {return data;}

		public void setData(int value) {this.data = value;}

		/**
		 * when commenting out this static builder method, then auto complete lists values as expected:
		 * "status", "data"
		 */
		public static DemoTypeWithBuilder.Builder<Void> builder() {
			return new DemoTypeWithBuilder.Builder<Void>(null, null, false);
		}

		public static class Builder<_B> {

			protected final _B _parentBuilder;
			protected final DemoTypeWithBuilder _storedValue;
			private String status;
			private int data;

			public Builder(final _B _parentBuilder, final DemoTypeWithBuilder _other, final boolean _copy) {
				this._parentBuilder = _parentBuilder;
				if (_other != null) {
					if (_copy) {
						_storedValue = null;
						this.status = _other.status;
						this.data = _other.data;
					} else {
						_storedValue = _other;
					}
				} else {
					_storedValue = null;
				}
			}

			/**
			 * when commenting out this constructor, then auto-complete lists:
			 * "_copy", "_other", "_parentBuilder"
			 */
			public Builder(final _B _parentBuilder, final DemoTypeWithBuilder _other, final boolean _copy, final PropertyTree _propertyTree, final
			PropertyTreeUse _propertyTreeUse) {
				this._parentBuilder = _parentBuilder;
				if (_other != null) {
					if (_copy) {
						_storedValue = null;
						final PropertyTree statusPropertyTree = ((_propertyTree == null) ? null : _propertyTree.get("status"));
						if (((_propertyTreeUse == PropertyTreeUse.INCLUDE) ? (statusPropertyTree != null) : ((statusPropertyTree == null) || (!statusPropertyTree.isLeaf())))) {
							this.status = _other.status;
						}
						final PropertyTree dataPropertyTree = ((_propertyTree == null) ? null : _propertyTree.get("data"));
						if (((_propertyTreeUse == PropertyTreeUse.INCLUDE) ? (dataPropertyTree != null) : ((dataPropertyTree == null) || (!dataPropertyTree.isLeaf())))) {
							this.data = _other.data;
						}
					} else {
						_storedValue = _other;
					}
				} else {
					_storedValue = null;
				}
			}

			protected <_P extends DemoTypeWithBuilder> _P init(final _P _product) {
				_product.status = this.status;
				_product.data = this.data;
				return _product;
			}

			public DemoTypeWithBuilder.Builder<_B> withStatus(final String status) {
				this.status = status;
				return this;
			}

			public DemoTypeWithBuilder.Builder<_B> withData(final int data) {
				this.data = data;
				return this;
			}

			public DemoTypeWithBuilder build() {
				if (_storedValue == null) {
					return this.init(new DemoTypeWithBuilder());
				} else {
					return _storedValue;
				}
			}
		}
	}

	// mock for com.kscs.util.jaxb.PropertyTreeUse
	public static class PropertyTreeUse {

	}

	// mock for com.kscs.util.jaxb.PropertyTree
	public static class PropertyTree {

	}
}
@thunderhook thunderhook changed the title Code Completion Code completion for target with generic builder not working Aug 4, 2021
filiphr added a commit that referenced this issue Aug 22, 2021
* Fix code completion for generic builder
* Fix code completion for builder with constructor parameters

Fixes #78
@filiphr filiphr added the bug label Aug 22, 2021
@filiphr filiphr added this to the 1.3.0 milestone Aug 22, 2021
@filiphr
Copy link
Member

filiphr commented Aug 22, 2021

Thanks for the detailed reproducal @thunderhook. It helped locate the problem. There were 2 problems actually:

  • We incorrectly use constructor parameters from the Builder class
  • Generic builder methods were not properly recognized

Just FYI, with the current builder the MapStruct processor will treat withStatus as a single property. Therefore, @Mapping(target = "status", source = "input") is not valid and it needs to be @Mapping(target = "withStatus", source = "input")

That is unless you have a custom AccessorNamingStrategy.

filiphr added a commit that referenced this issue Aug 22, 2021
* Fix code completion for generic builder
* Fix code completion for builder with constructor parameters

Fixes #78
@thunderhook
Copy link
Contributor Author

Thank your for the fix and the hint about the AccessorNamingStrategy. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants