You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
seems like annotation support is hot garbage, mostly it doesn't work as suggested it should (and isn't documented), and it requires you to duplicate every single annotation provided by an upstream framework. These days annotations are pretty much the #1 way that frameworks use to generate behavior, so not having fully working, fully documented first-class support for them doesn't really work (JPA support notwithstanding, at this exact second I was thinking of switching something over for Picocli, and realized what a pain.)
All we should generally have to do is annotate as normal, possibly adding an additional annotation saying where to put them.... in general though I think this entire mess needs to be rethought as to avoid having to have mylib:immutables, e.g. javax.validation:immutables, picocli:immutables just to provide a copy of annotations for every single upstream annotation.
at a thought, I would think that all you might need to add for non-repeatable's is a concrete (non-meta) annotation to say these go on a different generated thing, like the field. Maybe
// I'm changing the access type here from below@InjectAnnotation( type = Access.class, dest = InjectionAnnotation.Where.Field )
@Access(AccessType.FIELD)
CountrySubdivisionCodegetCode( );
and if you aren't moving it no need to specify an additional annotation.
At the end of this specialized Jackson support shouldn't be necesary.
from comment...
packagecom.mckesson.dex.annotation.jpa.immutables;
importjavax.persistence.AccessType;
importorg.immutables.annotate.InjectAnnotation;
@InjectAnnotation(type= javax.persistence.Access.class, target = { InjectAnnotation.Where.ACCESSOR, InjectAnnotation.Where.FIELD })
public @interface Access {
/** * (Required) Specification of field- or property-based access. */AccessTypevalue();
}
packagecom.mckesson.dex.model.principal;
importcom.google.common.base.MoreObjects;
importcom.google.errorprone.annotations.CanIgnoreReturnValue;
importcom.google.errorprone.annotations.Var;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.Objects;
importjavax.annotation.CheckReturnValue;
importjavax.annotation.Nullable;
importjavax.annotation.ParametersAreNonnullByDefault;
importjavax.annotation.concurrent.Immutable;
importjavax.annotation.concurrent.NotThreadSafe;
importjavax.persistence.Access;
importjavax.persistence.Cacheable;
importjavax.persistence.Column;
importjavax.persistence.Entity;
importjavax.persistence.Enumerated;
importjavax.persistence.Id;
importjavax.persistence.JoinTable;
importjavax.persistence.ManyToOne;
importorg.hibernate.annotations.Cache;
importorg.immutables.value.Generated;
/** * Immutable implementation of {@link CountrySubdivision}. * <p> * Use the builder to create immutable instances: * {@code ImmutableCountrySubdivision.builder()}. */@Generated(from = "CountrySubdivision", generator = "Immutables")
@SuppressWarnings({"all"})
@ParametersAreNonnullByDefault@javax.annotation.Generated("org.immutables.processor.ProxyProcessor")
@Immutable@CheckReturnValuepublicfinalclassImmutableCountrySubdivisionimplementsCountrySubdivision {
@AccessprivatefinalJurisdictionjurisdiction;
@Column@Enumerated@AccessprivatefinalCountrySubdivisionCodecode;
privateImmutableCountrySubdivision(
Jurisdictionjurisdiction,
CountrySubdivisionCodecode) {
this.jurisdiction = jurisdiction;
this.code = code;
}
/** * @return The value of the {@code jurisdiction} attribute */@Entity@ManyToOne@JoinTable@Cacheable@Cache@Access@OverridepublicJurisdictiongetJurisdiction() {
returnjurisdiction;
}
/** * @return The value of the {@code code} attribute */@Column@Entity@Cacheable@Enumerated@Cache@Id@Access@OverridepublicCountrySubdivisionCodegetCode() {
returncode;
}
/** * Copy the current immutable object by setting a value for the {@link CountrySubdivision#getJurisdiction() jurisdiction} attribute. * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}. * @param value A new value for jurisdiction * @return A modified copy of the {@code this} object */publicfinalImmutableCountrySubdivisionwithJurisdiction(Jurisdictionvalue) {
if (this.jurisdiction == value) returnthis;
JurisdictionnewValue = Objects.requireNonNull(value, "jurisdiction");
returnnewImmutableCountrySubdivision(newValue, this.code);
}
/** * Copy the current immutable object by setting a value for the {@link CountrySubdivision#getCode() code} attribute. * A value equality check is used to prevent copying of the same value by returning {@code this}. * @param value A new value for code * @return A modified copy of the {@code this} object */publicfinalImmutableCountrySubdivisionwithCode(CountrySubdivisionCodevalue) {
if (this.code == value) returnthis;
CountrySubdivisionCodenewValue = Objects.requireNonNull(value, "code");
if (this.code.equals(newValue)) returnthis;
returnnewImmutableCountrySubdivision(this.jurisdiction, newValue);
}
/** * This instance is equal to all instances of {@code ImmutableCountrySubdivision} that have equal attribute values. * @return {@code true} if {@code this} is equal to {@code another} instance */@Overridepublicbooleanequals(@NullableObjectanother) {
if (this == another) returntrue;
returnanotherinstanceofImmutableCountrySubdivision
&& equalTo((ImmutableCountrySubdivision) another);
}
privatebooleanequalTo(ImmutableCountrySubdivisionanother) {
returnjurisdiction.equals(another.jurisdiction)
&& code.equals(another.code);
}
/** * Computes a hash code from attributes: {@code jurisdiction}, {@code code}. * @return hashCode value */@OverridepublicinthashCode() {
@Varinth = 5381;
h += (h << 5) + jurisdiction.hashCode();
h += (h << 5) + code.hashCode();
returnh;
}
/** * Prints the immutable value {@code CountrySubdivision} with attribute values. * @return A string representation of the value */@OverridepublicStringtoString() {
returnMoreObjects.toStringHelper("CountrySubdivision")
.omitNullValues()
.add("jurisdiction", jurisdiction)
.add("code", code)
.toString();
}
/** * Creates an immutable copy of a {@link CountrySubdivision} value. * Uses accessors to get values to initialize the new immutable instance. * If an instance is already immutable, it is returned as is. * @param instance The instance to copy * @return A copied immutable CountrySubdivision instance */publicstaticImmutableCountrySubdivisioncopyOf(CountrySubdivisioninstance) {
if (instanceinstanceofImmutableCountrySubdivision) {
return (ImmutableCountrySubdivision) instance;
}
returnImmutableCountrySubdivision.builder()
.from(instance)
.build();
}
privatestaticfinallongserialVersionUID = 1L;
/** * Creates a builder for {@link ImmutableCountrySubdivision ImmutableCountrySubdivision}. * <pre> * ImmutableCountrySubdivision.builder() * .jurisdiction(com.mckesson.dex.model.principal.Jurisdiction) // required {@link CountrySubdivision#getJurisdiction() jurisdiction} * .code(com.mckesson.dex.model.principal.CountrySubdivisionCode) // required {@link CountrySubdivision#getCode() code} * .build(); * </pre> * @return A new ImmutableCountrySubdivision builder */publicstaticImmutableCountrySubdivision.Builderbuilder() {
returnnewImmutableCountrySubdivision.Builder();
}
/** * Builds instances of type {@link ImmutableCountrySubdivision ImmutableCountrySubdivision}. * Initialize attributes and then invoke the {@link #build()} method to create an * immutable instance. * <p><em>{@code Builder} is not thread-safe and generally should not be stored in a field or collection, * but instead used immediately to create instances.</em> */@Generated(from = "CountrySubdivision", generator = "Immutables")
@NotThreadSafepublicstaticfinalclassBuilder {
privatestaticfinallongINIT_BIT_JURISDICTION = 0x1L;
privatestaticfinallongINIT_BIT_CODE = 0x2L;
privatelonginitBits = 0x3L;
private@NullableJurisdictionjurisdiction;
private@NullableCountrySubdivisionCodecode;
privateBuilder() {
}
/** * Fill a builder with attribute values from the provided {@code CountrySubdivision} instance. * Regular attribute values will be replaced with those from the given instance. * Absent optional values will not replace present values. * @param instance The instance from which to copy values * @return {@code this} builder for use in a chained invocation */@CanIgnoreReturnValuepublicfinalBuilderfrom(CountrySubdivisioninstance) {
Objects.requireNonNull(instance, "instance");
jurisdiction(instance.getJurisdiction());
code(instance.getCode());
returnthis;
}
/** * Initializes the value for the {@link CountrySubdivision#getJurisdiction() jurisdiction} attribute. * @param jurisdiction The value for jurisdiction * @return {@code this} builder for use in a chained invocation */@CanIgnoreReturnValuepublicfinalBuilderjurisdiction(Jurisdictionjurisdiction) {
this.jurisdiction = Objects.requireNonNull(jurisdiction, "jurisdiction");
initBits &= ~INIT_BIT_JURISDICTION;
returnthis;
}
/** * Initializes the value for the {@link CountrySubdivision#getCode() code} attribute. * @param code The value for code * @return {@code this} builder for use in a chained invocation */@CanIgnoreReturnValuepublicfinalBuildercode(CountrySubdivisionCodecode) {
this.code = Objects.requireNonNull(code, "code");
initBits &= ~INIT_BIT_CODE;
returnthis;
}
/** * Builds a new {@link ImmutableCountrySubdivision ImmutableCountrySubdivision}. * @return An immutable instance of CountrySubdivision * @throws java.lang.IllegalStateException if any required attributes are missing */publicImmutableCountrySubdivisionbuild() {
if (initBits != 0) {
thrownewIllegalStateException(formatRequiredAttributesMessage());
}
returnnewImmutableCountrySubdivision(jurisdiction, code);
}
privateStringformatRequiredAttributesMessage() {
List<String> attributes = newArrayList<>();
if ((initBits & INIT_BIT_JURISDICTION) != 0) attributes.add("jurisdiction");
if ((initBits & INIT_BIT_CODE) != 0) attributes.add("code");
return"Cannot build CountrySubdivision, some of required attributes are not set " + attributes;
}
}
}
I also tried code="[[*]]" and it generated it as @Accessvalue = AccessType.FIELD` with the right import, but that's not a valid annotation usage. If I do this
Another consideration is to create multi-annotation injection and precondition it on the presence of the annotation itself
@InjectAnnotation(
type = Access.class,
target = {InjectAnnotation.Where.FIELD, InjectAnnotation.Where.ACCESSOR},
ifPresent = true
)
@InjectAnnotation(
type = SomeOtherAnnotation.class,
target = {InjectAnnotation.Where.FIELD},
ifPresent = true
)
public @interface MyAssessEtc {
}
notice that the code= is not specified, so it just copy original annotations with all their attributes. No need to create a bunch of custom annotations. In this way you can create "annotation injection library" annotation(s) and place it('em) on the type or even package (package-info.java, need to check but it will probably work too).
@Value.Immutable@MyAccessEtcpublicinterfaceAnnotatedEntityextendsSerializable {
@Access(AccessType.FIELD) //<-- will get copied to the field and accessorStringgetJurisdiction();
@Access(AccessType.PROPERTY) //<-- will get copied to the field and accessorStringgetCode();
}
If you have multiple rules which can clash and inject many of the "same" or conflicting annotations, you can use InjectAnnotation.deduplicationKey to limit to a single "closest" rule.
seems like annotation support is hot garbage, mostly it doesn't work as suggested it should (and isn't documented), and it requires you to duplicate every single annotation provided by an upstream framework. These days annotations are pretty much the #1 way that frameworks use to generate behavior, so not having fully working, fully documented first-class support for them doesn't really work (JPA support notwithstanding, at this exact second I was thinking of switching something over for Picocli, and realized what a pain.)
All we should generally have to do is annotate as normal, possibly adding an additional annotation saying where to put them.... in general though I think this entire mess needs to be rethought as to avoid having to have
mylib:immutables
, e.g.javax.validation:immutables
,picocli:immutables
just to provide a copy of annotations for every single upstream annotation.at a thought, I would think that all you might need to add for non-repeatable's is a concrete (non-meta) annotation to say these go on a different generated thing, like the field. Maybe
and if you aren't moving it no need to specify an additional annotation.
At the end of this specialized Jackson support shouldn't be necesary.
from comment...
given this entity:
it generated this code
I also tried
code="[[*]]" and it generated it as
@Accessvalue = AccessType.FIELD` with the right import, but that's not a valid annotation usage. If I do thisit generates the proper annotation on the field but leaves out the import.
version
2.8.2
Originally posted by @xenoterracide in #903 (comment)
The text was updated successfully, but these errors were encountered: