Hi Nikita, hi Michael, I took some days to get a deeper grasp of what I’m dealing with so that hopefully I don’t say something stupid.
Thank you for pointing out the existence of a the ExtendedTypeFactory class. I had missed it entirely and I can see its purpose now. I still can’t properly overcome the issue of the non-extendable EnumSet class. The problem is mainly that I need to somehow bring along the Enum type as it is needed to instantiate an EnumSet. You can’t just do new EnumSet(). The only way is to call static EnumSet.noneOf(Class<E> enumType). So enumType must be known. For regular collections, what I do is to extend an existing collections like this: public class StringList extends ArrayList<String> public class StringSet extends HashSet<String> Is that the intended way to deal with a collection-like object? Anyway, I can’t extend EnumSet so that solution is not on the table. What I did try is to use a fake cover-up class that DOES NOT extend EnumSet. I created: public abstract static class FakeEnumSet<E extends Enum<E>> extends HashSet<E> And then for each Enum I created a placeholder class that extends FakeEnumSet and use that one in the model. This way I can either register directly or via factory and infer the Enum type. That’s ugly. I also hit another wall in the implementation of my EnumSetExtendedType class. Assuming the class is aware of the right Enum type via subclassing, I still can’t return an EnumSet as the result of materializeObject(). If I do so then later on the class generated stuff from the modeller attempts to cast the value into the one indicated in the model and fails because EnumSet cannot be casted into FakeEnumSet. This last thing I might be able to workaround by playing with the class templates, haven’t tried yet. For now the only solution I managed to get working is to actually instantiate FakeEnumSet and then convert it from there to EnumSet later in the code. Not ideal because I’m basically doing things two times. Overall what I feel is missing is the option to use a generic-like syntax in the modeller. If we could write java.util.EnumSet<Color> as the class and then get this Color bit later in the ExtendedTypeFactory, then we would be able to instantiate the EnumSet and populate it with the right Enum entries. More than for just the EnumSet case, it would work wonders for ALL the Collections in general. Think things like these that I use all the time java.util.List<String> for list of strings java.util.List<Integer> for list of numbers java.util.List<LocalDateTime> for list of dates No need to create cover-up classes or extend anything. I was looking at the Cayenne source for the: protected ExtendedType createType(String className) in ExtendedTypeMap It converts the className to a Class object and then invokes all the ExtendedTypeFactories with it. If it passed the string instead of the class the factory would have the option of processing the type between < > and then strip it. Is it difficult to implement? Am I being naive? Thank you, Riccardo > On 7 Apr 2025, at 17:58, Nikita Timofeev <ntimof...@objectstyle.com> wrote: > > Hello Riccardo, > > It should be possible to support EnumSet with ExtendedType. > I did some prototyping, and it looks like you need to implement these parts: > > 1. an ExtendedTypeFactory as EnumSet has internal subclasses (that also > prevents using ValueType for this): > > public ExtendedType getType(Class<?> objectClass) { > if(EnumSet.class.isAssignableFrom(objectClass)) { > return new EnumSetType(); > } > return null; > } > > 2. an ExtendedType should deal with the serialization to/from the actual > datatype you are using in the DB: > > public class EnumSetType implements ExtendedType<EnumSet> { > @Override > public void setJdbcObject(PreparedStatement statement, EnumSet value, int > pos, int type, int scale) throws Exception { > statement.setString(pos, toString(value)); > } > > @Override > public EnumSet<?> materializeObject(ResultSet rs, int index, int type) > throws Exception { > return fromString(rs.getString(index)); > } > > String toString(EnumSet value) { > // probably should account for the Enum type > } > > EnumSet fromString(String value) { > } > } > > 3. and finally register factory with the runtime: > > ServerModule.contributeTypeFactories(binder) > .add(new EnumSetFactory()) > > Hope this helps! > > On Sat, Apr 5, 2025 at 8:03 PM Riccardo De Menna <deme...@tuorlo.net> wrote: > >> Hello, >> >> I was wondering if there is a way to add a custom data type for a non >> extendable class. Specifically I’m thinking of java.util.EnumSet. >> >> I often use Enums in my object classes and I occasionally employ EnumSets >> when the case requires it. Unfortunately EnumSet is non extendable so I >> can’t define a subclass and then use that as java type in the modeller. >> >> Is there a way to hack the runtime into returning an EnumSet using a >> custom ValueType or ExtenedType for multiple attributes (it does work if >> there’s only one attribute using EnumSet but as soon as you define two the >> runtime gets confused). >> >> At the moment I’m just extending a HashSet<E extends Enum<E>> as a >> workaround but every time I see that I feel guilty not being able to use >> the ‘proper’ set collection for enums. >> >> Thank you, >> Riccardo De Menna > > > > -- > Best regards, > Nikita Timofeev