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

Bug on @Getter(lazy=true) and transient fields #1236

Closed
manuel-hegner opened this issue Nov 17, 2016 · 7 comments
Closed

Bug on @Getter(lazy=true) and transient fields #1236

manuel-hegner opened this issue Nov 17, 2016 · 7 comments

Comments

@manuel-hegner
Copy link

Hey,
there is a problem that occurs if you have a transient field that is laziely initialized. The generated getter method crashes after deserialization because the field is null. The expected behaviour would be to call the lazy creationmethod again.

So instead of generating something like:

public double[] getCached() {
	java.lang.Object value = this.cached.get();
	if (value == null) {
		synchronized(this.cached) {
			value = this.cached.get();
			if (value == null) {
				final double[] actualValue = expensive();
				value = actualValue == null ? this.cached : actualValue;
				this.cached.set(value);
			}
		}
	}
	return (double[])(value == this.cached ? null : value);
} 

It should be something like this, at least for transient values:

public double[] getCached() {
	if(cached==null) {
		synchronized(this) {
			if(cached==null)
				cached = new java.util.concurrent.AtomicReference<java.lang.Object>();
		}
	}
	java.lang.Object value = this.cached.get();
	if (value == null) {
		synchronized(this.cached) {
			value = this.cached.get();
			if (value == null) {
				final double[] actualValue = expensive();
				value = actualValue == null ? this.cached : actualValue;
				this.cached.set(value);
			}
		}
	}
	return (double[])(value == this.cached ? null : value);
} 
@m4gshm
Copy link
Contributor

m4gshm commented Nov 21, 2016

cached = new java.util.concurrent.AtomicReference<java.lang.Object>();
It does not compile because the field is final.

@manuel-hegner
Copy link
Author

Oh yeah. I forgot that the field is final. So to prevent the serialization bug you could either make it not final or you have to create a totally different way to serialize/deserialize this.

Another way would be to add an error if a lazy getter field is transient.

@Maaartinus
Copy link
Contributor

I'm afraid the field must be final in order to be visible in other threads (I guess, it could be volatile instead).

Serialization is a dirty beast and AFAIK uses some kind of reflection for setting final fields. This is probably what also lombok should do for transient fields. I believe that there are no visibility issues (as reflection emits the memory barrier needed).

A compile-time error is IMHO a good step before a better solution gets implemented.

@rspilker
Copy link
Collaborator

rspilker commented Dec 5, 2016

Using reflection in a readResolve method that also should be generated if it's not already there, or added to an existing readResolve is for us way too much effort for use case that we didn't encounter a lot. So we chose to give a compile time error instead.

teosarca added a commit to metasfresh/metasfresh that referenced this issue Apr 8, 2017
@deinspanjer
Copy link

Oy. I just tried upgrading my Lombok dependency to 1.16.16 and hit this error.
I have several fields which need to be lazily initialized, but they need to be transient because I don't want those fields to be read by Gson when converting the object to JSON.

Any tips on a way around this other than downgrading?

@DramaFire
Copy link

Oy. I just tried upgrading my Lombok dependency to 1.16.16 and hit this error.
I have several fields which need to be lazily initialized, but they need to be transient because I don't want those fields to be read by Gson when converting the object to JSON.

Any tips on a way around this other than downgrading?
You can create a class A containning those fields to be lazily initialized, then declare the instance of class A being final and transient as a object of the class to be serialized.

@rspilker
Copy link
Collaborator

rspilker commented Mar 5, 2019

You could modify your Gson to exclude certain fields from serialization.

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

No branches or pull requests

6 participants