Open msqr opened 4 years ago
Matt, Thanks a lot for your question. You are scratching an older itch I'm afraid and the Java language itself has no real solution here at runtime, see a recent analysis: https://stackify.com/jvm-generics-type-erasure/ None of the solutions work really well without either passing the type in every case (instead of a class this is also what ICU4J does) or being restricted to a special condition like inline code or static methods where the generic type may sometimes be available via Reflection.
All in all, that is a question for future Java releases, Project Valhalla (I did some very early experiments with it here: https://github.com/unitsofmeasurement/uom-demos/tree/master/console/valhalla) may help, but it is not yet clear, which aspects of it make it into a future JDK and which version. So I put a deferred label on it, we only finalized JSR 385, so it might have a bit of time anyway. Without changing the API we could try to help with that in the RI, e.g. AbstractSystemOfUnits
, so please feel free to create a similar ticket in https://github.com/unitsofmeasurement/indriya/issues. That class has a getUnit(Class)
method already, but it could be an option to add a getUnits(Class)
method returning a Set or Collection like getUnits(Dimension)
does there already. The existing method only returns the system or base unit for the given quantity type. We would have to store the meta-information like the type class for every unit (otherwise it would not be in such collection) but it could offer a way to retrieve all units for a given type until Java allows to get that information more explicitly from the Unit
or Quantity
itself.
Actually I think https://github.com/unitsofmeasurement/indriya/issues/224 might be a ticket for that already. It's phrased very "thin" but I would interpret "list of all valid Dimension for a Quantity LENGTH..." as list of valid units for a Quantity Length
, because a Unit
only has one Dimension
, and while LENGTH
is also a Dimension
instance, a method that returns all units for a given dimension like that already exists. It doesn't for a given quantity class because that meta-information is not stored so far.
Hi Werner, thanks for your response. I've dealt with erasure problems like this, I understand what you mean. I guess I was wishing the Unit
API could provide the Quantity
class directly, something like
Class<Q> getQuantityClass();
Which would of course require all Unit
implementations to capture that class at construction time, as you note, for example in AbstractUnit
private final Class<Q> quantityClass;
/**
* Constructor.
*
* @param quantityClass the quantity class.
*/
protected AbstractUnit(Class<Q> quantityClass) {
this.quantityClass = quantityClass;
}
/**
* Constructor setting a symbol.
*
* @param quantityClass the quantity class.
* @param symbol the unit symbol.
*/
protected AbstractUnit(Class<Q> quantityClass, String symbol) {
this.quantityClass = quantityClass;
this.symbol = symbol;
}
public Class<Q> getQuantityClass() {
return quantityClass;
}
I understand that impacts all implementations of Unit
but does not impact consumers of the API (other that the added getQuantityClass()
method). This would then continue to support Java 8.
This issue comes up for me on a project where I need to deal with arbitrary, user-configured units defined as strings so that I can later capture amount values associated with those units into Quantity
instances and translate them into system or base units.
Thanks again for the info; it looks like for now I will need to use Indriya directly. Perhaps a tweak to the Unit
API like discussed here could happen in the future.
I'm not sure if Class<Q>
would work because the problem is, Q at runtime usually gets deleted even if you try to store the class, Class would but then one had to store e.g. Length
etc. everywhere. For Unit because that comes from a registry like Units
or another system, it could work, but it would be a redundancy.
Hello, I am not finding how to resolve a
Quantity<?>
instance if I am starting with aNumber
and aUnit<?>
instance, using only thejavax.measure
API. The trouble here is that I don't know theQuantity
class at runtime, so I can't calljavax.measure.spi.ServiceProvider.getQuantityFactory(Class<Q> quantity)
to get the appropriateQuantityFactory
on which I could calljavax.measure.spi.QuantityFactory.create(Number value, Unit<Q> unit)
.I don't know there is a very easy way using Indriya:
tech.units.indriya.quantity.Quantities.getQuantity(Number value, Unit<Q> unit)
but I am trying to understand how to achieve the same thing with only thejavax.measure
API. Could you point me in the right direction?