JadiraOrg / jadira

Jadira Framework
Apache License 2.0
74 stars 45 forks source link

Support JSR385/JSR363/JSR275/JScience usertype for Unit class #15

Closed ceefour closed 6 years ago

ceefour commented 10 years ago

Proposed implementation :

https://github.com/soluvas/soluvas-framework/blob/master/jpa/src/main/java/org/soluvas/jpa/PersistentUnit.java

Dependency:

                    <dependency>
            <groupId>org.jscience</groupId>
            <artifactId>jscience</artifactId>
            <version>4.3.1</version>
          <optional>true</optional>
        </dependency>

Optional dependency so that projects not requiring jscience do not need to depend on it.

chrisphe commented 10 years ago

To add JScience support more than Unit needs supporting. I think that a heuristic type along the lines of PersistentEnum ought to be added for Measure (DecimalMeasure, DoubleMeasure, FloatMeasure, IntegerMeasure, LongMeasure, VectorMeasure) with the option of overriding the configured methods for customisation. A similar approach can be taken for Coordinates (Altitude, Height, LatLong etc) so that a single customisable user type could support them and Amount (including Time).

So - this could be generalised to a straightforward usertype for Unit and a heuristic type for Measurable.

ceefour commented 10 years ago

Thank you..

Unit can also be treated as heuristic "dynamic enum" type (a la PersistentCurrencyUnit) and the implementation UserType can be used for many things. However I still suggest for shortcuts for JScience/JSR275 (i.e. PersistentUnit as subclass of the heuristic UserType) because these classes are widely used.

Commonality of 'dynamic enums' (but they're not Java Enums but custom classes, so PersistentEnum cannot be used):

  1. 80% of cases these are persisted as VARCHAR in database. for example, a Unit<?> (unknown dimension) due to dynamic nature of combined units, it's not feasible to use e.g. ENUM type
  2. 20% of cases can use e.g. ENUM in database for restricted schemas (i.e. Unit<Length>, Unit<Temperature>) ... In this case, another UserType for PostgreSQL (#14) would be good that persists to ENUM instead of VARCHAR

If a heuristic UserType implementation is used it means app developers can persist their own "dynamic enums" easily, without having to write their own UserType every time. :+1: An example on top of my head is java.util.Locale, and there's no PersistentLocale in jadira...

Adding Measure, Coordinate, etc. would be even more awesome, since it builds upon the UserType unit (both VARCHAR and ENUM variants). BTW for Measure, I would be more inclined to use ENUM instead of VARCHAR (but both should be supported), since most likely it'll be used to store a specific dimension, i.e. length, weight, etc. which means the units are restricted and can fit into ENUM, which in ENUM-supporting databases (like PostgreSQL) are much more efficient than VARCHAR.

FrEaKmAn commented 9 years ago

are there any updates about this? having jadira together with jscience would be a really nice feature.

chrisphe commented 9 years ago

Leaving this open as a potential future feature

keilw commented 9 years ago

This no longer makes sense, please support JSR 363 instead (it's about to reach Public Draft before the end of 2015, likely around JavaOne, first projects like Duke Award winning OpenHab/Eclipse SmartHome already started adopting 363, too) The JSR 363 EG and Spec Leads are happy to help.

chrisphe commented 9 years ago

Thanks, will take a look. Are you also involved in 363?

keilw commented 9 years ago

Indeed, I'm one of the Spec Leads;-) See https://jcp.org/en/jsr/detail?id=363

chrisphe commented 8 years ago

Werner, Having looked into this I think it will be tricky for a general solution. Its to do with the extensible nature of JSR 363's API compared with Hibernate's need to deal with concrete types. Happy to discuss further, there may be something that can be done around this with Heuristic or Reflection types.

chrisphe commented 8 years ago

@ceefour If you are interested in working towards a pr for this, I will assist as I am able

keilw commented 8 years ago

It's not really much more extensible than JSR 354 in its core types Unit or Quantity. There are use cases (e.g. UCUM parsers including those to JSON thaks to Opower) where generic types play practically no role, so you get down to just those two basic types similar to what's been done with JSR 354 (here or by Zalando) already. Happy to help or discuss possible solutions.

keilw commented 6 years ago

@chrisphe Is Jadira still actively developed? JSR 363 went final the same day as the last version of Jadira. Looks like there was no activity for a year now.

chrisphe commented 6 years ago

@keilw I never got around to looking at this, but would still like to so... left the issue open. Thanks for the nudge.

keilw commented 6 years ago

Actually, the safest and most future-proof option would be using Indriya 1.0 now ;-) https://github.com/unitsofmeasurement/indriya is a fully compliant TCK compatible "backport" of the next RI (for JSR 385, which is scheduled to finish about a year from now just in time for the biggest Metric System reform since the SI System was introduced in 1960) so you can use it now with JSR 363 and only have to update dependency numbers later for 385. Would that sound convenient for Jadira?

ceefour commented 6 years ago

@keilw Thanks for the update. It seems that JSR363 had the shortest lifespan ever. :D

keilw commented 6 years ago

@ceefour Not at all compared to the average JSF JSRs https://en.wikipedia.org/wiki/JavaServer_Faces 2.0 and 2.1 were just a year apart! Or what we now see with JSR 383 and 384. Each meant to last only 6 months ;-D By using Indriya you can be sure to be future-proof both when it comes to the Unit API and underlying JDK version(s)

chrisphe commented 6 years ago

I've added an initial implementation for Indriya. Mostly I've been able to avoid using implementation rather than TCK classes, other than Units and Quantities @keilw Any way I can avoid these uses?

chrisphe commented 6 years ago

If additional SQL column types should be supported, please create those as new issues

keilw commented 6 years ago

@chrisphe Yes, you can call

QuantityFactory<Length> qfl = ServiceProvider.current().getQuantityFactory(Length.class);
Quantity<Length> oneMetre = qfl.create(1, METRE);

Which still uses the Units class, but this can also be done via SPI

SystemOfUnits metricSystem = ServiceProvider.current().getSystemOfUnitsService().
   getSystemOfUnits();
Unit<Length> metre = metricSystem.getUnit(Length.class);

As long as you're fine with the default (base) unit, this is the easiest way to retrieve it via the SPI.

For other units it is currently necessary to look it up from the set of units

Unit<?> metre;
SystemOfUnits metricSystem = ServiceProvider.current().getSystemOfUnitsService().
   getSystemOfUnits();
for (Unit u: metricSystem.getUnits()) {
  if ("m".equals(u.getSymbol()) {
    metre = u;
    break;
  }
}

We might add a convenience method like getUnit(String key) to SystemOfUnits allowing to do this more easily for other units, but even with Lambdas some of those could be reduced to a line or two.

chrisphe commented 6 years ago

@keilw So, currently, I have this one line:

Quantities.getQuantity(val + " " + unit.getSymbol());

So, I'm still unclear how to obtain a Quantity when I only have a value and a unit (not the parameterized type of the quantity).

As far as I can see I need to know the class that corresponds to the Unit (which I don't have apriori).

keilw commented 6 years ago

@chrisphe Without the class, that's a good question. I don't think the API/SPI might work because QuantityFactory is type-safe. I don't think there is a way around it right now.

We could think of something in 2.0 e.g. additional methods on ServiceProvider. If you want propose something in https://github.com/unitsofmeasurement/unit-api/issues.

chrisphe commented 6 years ago

@keilw No problem, for now I've only supported Indriya. The old UoM reference implementation also provides the same method (in a similar package) so it wouldn't be massively painful to support it if someone needs that. JScience I will likely not adopt into Jadira (I assume you don't see a strong driver for that since its effectively deprecated by the subsequent JSRs I think?).

If you do support a non-type space creation of a quantity in the API/SPI, the implementation can be portable between UoM providers.