swagger-codegen icon indicating copy to clipboard operation
swagger-codegen copied to clipboard

[Java] Generate copy constructor in models

Open asarazan opened this issue 9 years ago • 6 comments

Description

Java models should have a way to easily create a clone or copy. Cloneable seems like a bad idea so I think we're probably left with a copy function or copy constructor.

I couldn't find anything in issues search. Has this been suggested before?

asarazan avatar Sep 28 '16 00:09 asarazan

@asarazan I don't recall anyone suggesting something similar.

Just so you know we can make the model "Serializable" by switching on an option. For cloneable or copy we can do something similar.

wing328 avatar Sep 28 '16 10:09 wing328

That sounds good. I've been re-reading the Effective Java entry on Cloneable and I'm convinced it's probably the wrong decision:

Suppose you want to make this class cloneable. If its clone method merely returns super.clone() , the resulting Stack instance will have the correct value in its size field, but its elements field will refer to the same array as the original Stack instance. Modifying the original will destroy the invariants in the clone and vice versa. You will quickly find that your program produces nonsensical results or throws a NullPointerException .

So it looks like anything with mutable state becomes very very fragile with clone. It seems like the best way forward is to generate a field-by-field copy constructor for each model, which defensively deep copies each property.

Alternately, a good (but difficult) long-term solution would be to re-architect models as immutable data objects with a builder pattern for mutation-- e.g. how protocol buffers is implemented.

asarazan avatar Sep 28 '16 17:09 asarazan

One good use case for this is if you are accessing the swagger endpoint with different host names and want the host name to be based on the request URI's host. I think we just need a shallow copy constructor. Something like withBaseUri

trajano avatar Oct 04 '17 01:10 trajano

package net.trajano.ms.engine.internal.swagger;

import java.net.URI;
import java.util.Arrays;

import io.swagger.models.Scheme;
import io.swagger.models.Swagger;

public class ClonableSwagger extends Swagger {

    /**
     * Creates a shallow copy of the swagger but set the scheme, host and base path
     * to the base URI
     *
     * @param baseUri
     *            base URI
     * @return shallow copy
     */
    public ClonableSwagger withBaseUri(final URI baseUri) {

        final ClonableSwagger copy = new ClonableSwagger();
        copy.swagger = swagger;
        copy.info = info;
        if (baseUri.getPort() > 0) {
            copy.host = baseUri.getHost() + ":" + baseUri.getPort();
        } else {
            copy.host = baseUri.getHost();
        }
        copy.basePath = baseUri.getPath();
        copy.tags = tags;
        copy.schemes = Arrays.asList(Scheme.forValue(baseUri.getScheme()));
        copy.consumes = consumes;
        copy.produces = produces;
        copy.security = security;
        copy.paths = paths;
        copy.securityDefinitions = securityDefinitions;
        copy.definitions = definitions;
        copy.parameters = parameters;
        copy.responses = responses;
        copy.externalDocs = externalDocs;
        copy.vendorExtensions = vendorExtensions;
        return copy;
    }

}

trajano avatar Oct 04 '17 01:10 trajano

Any news about this ? I need to clone Schema object, should i make an utility method to clone this object in my project, or do you want a pull request with this kind of feature ?

quen2404 avatar Jul 11 '18 09:07 quen2404

I checked serialization part and made little util function for creating copy for editing

private <T> T getCopy(T src) {
	Gson gson=yourWayForGettingApiClient().getJSON().getGson();
	String s=gson.toJson(src);
	Class<T> clazz=(Class<T>) src.getClass();
	T copy=gson.fromJson(s,clazz);
	return copy;
}

simo-11 avatar Nov 29 '19 12:11 simo-11