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

Does Contraband Generated No-Arg Constructors for Java POJOs #144

Open
mikail-khan opened this issue Jan 31, 2020 · 3 comments
Open

Does Contraband Generated No-Arg Constructors for Java POJOs #144

mikail-khan opened this issue Jan 31, 2020 · 3 comments

Comments

@mikail-khan
Copy link

Hi,

I read the docs and looked at the source, am I right in thinking that contraband does not generate no-arg constructor for Java classes?

If not, how much work would be required to do that. I could raise a PR if you could give me some guidelines.

The reason for requesting this is that it would make interop with certain Java libraries which require POJOs (with a no-arg constructor mandatory) easier to deal with in Scala projects.

@eed3si9n
Copy link
Member

It generates something like this when there's no field:

package xsbti.api;
public final class This extends xsbti.api.PathComponent {
    
    public static This create() {
        return new This();
    }
    public static This of() {
        return new This();
    }
    
    protected This() {
        super();
        
    }
    
    
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        } else if (!(obj instanceof This)) {
            return false;
        } else {
            This o = (This)obj;
            return true;
        }
    }
    public int hashCode() {
        return 37 * (17 + "xsbti.api.This".hashCode());
    }
    public String toString() {
        return "This("  + ")";
    }
} 

@mikail-khan
Copy link
Author

Yeah, but I would like the case where there are fields but it sticks in a no-arg constructor in as well. Something like this:

import java.util.List;
import java.util.Objects;

/** Represents a city : name, weather, population, country, capital, geo coordinates. */
public class City {

  private String name;
  private String state;
  private String country;
  private Boolean capital;
  private Long population;
  private List<String> regions;

  // [START fs_class_definition]
  public City() {
    // Must have a public no-argument constructor
  }

  // Initialize all fields of a city
  public City(String name, String state, String country,
              Boolean capital, Long population, List<String> regions) {
    this.name = name;
    this.state = state;
    this.country = country;
    this.capital = capital;
    this.population = population;
    this.regions = regions;
  }
  // [END fs_class_definition]

  public City(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getState() {
    return state;
  }

  public void setState(String state) {
    this.state = state;
  }

  public String getCountry() {
    return country;
  }

  public void setCountry(String country) {
    this.country = country;
  }

  public Boolean getCapital() {
    return capital;
  }

  public void setCapital(Boolean capital) {
    this.capital = capital;
  }

  public Long getPopulation() {
    return population;
  }

  public void setPopulation(Long population) {
    this.population = population;
  }

  public List<String> getRegions() {
    return regions;
  }

  public void setRegions(List<String> regions) {
    this.regions = regions;
  }

  private String getDefinedValue(String s) {
    if (s != null) {
      return s;
    } else {
      return "";
    }
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    if (name != null) {
      sb.append(name);
    }
    if (state != null) {
      sb.append(" state : ");
      sb.append(state);
      sb.append(",");
    }
    if (country != null) {
      sb.append(", ");
      sb.append(country);
    }
    sb.append(" : [");
    if (population != null) {
      sb.append(" population : ");
      sb.append(population);
      sb.append(",");
    }
    if (capital != null) {
      sb.append(" capital : ");
      sb.append(capital);
      sb.append(",");
    }
    if (regions != null) {
      sb.append(" regions : [");
      for (String r : regions) {
        sb.append(r);
        sb.append(", ");
      }
      sb.append("],");
    }
    //remove trailing comma
    if (sb.lastIndexOf(",") >= sb.length() - 1) {
      sb.deleteCharAt(sb.length() - 1);
    }
    sb.append(" ]");
    return sb.toString();
  }

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof City)) {
      return false;
    }
    City city = (City) obj;
    return Objects.equals(name, city.name)
        && Objects.equals(state, city.state)
        && Objects.equals(country, city.country)
        && Objects.equals(population, city.population)
        && Objects.equals(capital, city.capital)
        && Objects.equals(regions, city.regions);
  }

  @Override
  public int hashCode() {
    return Objects.hash(name, state, country, capital, population, regions);
  }
}

@eed3si9n
Copy link
Member

zero-field builder

Contraband generates multiple of methods using @since but I didn't think about the blank case where at some version X there are no fields, and version Y adds some fields. This needs to be fixed first.

package com.example
@target(Scala)

type City {
  name: String! = "" @since("0.2.0")
}

Maybe we can introduce @since to records:

package com.example
@target(Scala)

type City
@since("0.1.0")
{
  name: String! = "" @since("0.2.0")
}

of vs constructor

We currently don't directly expose the constructor, and use factory method of.

Generally I think it's better to add indirection here for potentially being able to change the implementation (historically Contraband was created to workaround Scala's inability to grow case classes). We could potentially add some setting for this, but I am not sure if having a no-arg constructor would be useful since Contraband objects don't act like POJO. See below.

setter

We also don't support setters. All objects are immutable.

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

2 participants