001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2023, Jean-Marie Dautelle, Werner Keil, Otavio Santana. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-385, Indriya nor the names of their contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tech.units.indriya.unit; 031 032import javax.measure.Dimension; 033import javax.measure.Quantity; 034import javax.measure.Unit; 035import javax.measure.UnitConverter; 036 037import tech.units.indriya.AbstractUnit; 038 039import java.util.Map; 040import java.util.Objects; 041 042/** 043 * <p> 044 * This class represents units used in expressions to distinguish between 045 * quantities of a different nature but of the same dimensions. 046 * </p> 047 * 048 * <p> 049 * Examples of alternate units: 050 * </p> 051 * 052 * <code> 053 * {@literal Unit<Angle>} RADIAN = AlternateUnit.of(ONE, "rad").asType(Angle.class);<br> 054 * {@literal Unit<Force>} NEWTON = AlternateUnit.of(METRE.multiply(KILOGRAM).divide(SECOND.pow(2)), "N").asType(Force.class);<br> 055 * {@literal Unit<Pressure>} PASCAL = AlternateUnit.of(NEWTON.divide(METRE.pow(2), "Pa").asType(Pressure.class);<br> 056 * </code> 057 * 058 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 059 * @author <a href="mailto:werner@units.tech">Werner Keil</a> 060 * @version 2.0, February 08, 2020 061 * @since 1.0 062 */ 063public final class AlternateUnit<Q extends Quantity<Q>> extends AbstractUnit<Q> { 064 065 /** 066 * 067 */ 068 private static final long serialVersionUID = 4696690756456282705L; 069 070 /** 071 * Holds the parent unit (a system unit). 072 */ 073 private final Unit<?> parentUnit; 074 075 /** 076 * Creates an alternate unit for the specified system unit identified by the 077 * specified name and symbol. 078 * 079 * @param parentUnit the system unit from which this alternate unit is derived. 080 * @param symbol the symbol for this alternate unit. 081 * @throws IllegalArgumentException if the specified parent unit is not an 082 * {@link AbstractUnit#isSystemUnit() system 083 * unit} 084 */ 085 @SuppressWarnings("rawtypes") 086 public AlternateUnit(Unit<?> parentUnit, String symbol) { 087 super(symbol); 088 if (!(parentUnit instanceof AbstractUnit)) 089 throw new IllegalArgumentException("The parent unit: " + parentUnit + " is not an AbstractUnit"); 090 if (!((AbstractUnit) parentUnit).isSystemUnit()) 091 throw new IllegalArgumentException("The parent unit: " + parentUnit + " is not an unscaled SI unit"); 092 this.parentUnit = parentUnit instanceof AlternateUnit ? ((AlternateUnit) parentUnit).getParentUnit() 093 : parentUnit; 094 } 095 096 /** 097 * Creates an alternate unit for the specified system unit identified by the 098 * specified name and symbol. 099 * 100 * @param parentUnit the system unit from which this alternate unit is derived. 101 * @param symbol the symbol for this alternate unit. 102 * @param name the name for this alternate unit. 103 * @throws IllegalArgumentException if the specified parent unit is not an 104 * {@link AbstractUnit#isSystemUnit() system 105 * unit} 106 * @since 2.0 107 */ 108 AlternateUnit(Unit<?> parentUnit, String symbol, String name) { 109 this(parentUnit, symbol); 110 this.name = name; 111 } 112 113 /** 114 * Returns the parent unit of this alternate unit, always a system unit and 115 * never an alternate unit. 116 * 117 * @return the parent unit. 118 */ 119 public Unit<?> getParentUnit() { 120 return parentUnit; 121 } 122 123 @Override 124 public Dimension getDimension() { 125 return parentUnit.getDimension(); 126 } 127 128 @SuppressWarnings("rawtypes") 129 @Override 130 public UnitConverter getSystemConverter() { 131 return ((AbstractUnit) parentUnit).getSystemConverter(); 132 } 133 134 @Override 135 public Unit<Q> toSystemUnit() { 136 return this; // Alternate units are SI units. 137 } 138 139 @Override 140 public Map<? extends Unit<?>, Integer> getBaseUnits() { 141 return parentUnit.getBaseUnits(); 142 } 143 144 @Override 145 public int hashCode() { 146 return Objects.hash(parentUnit, getSymbol()); 147 } 148 149 @SuppressWarnings("rawtypes") 150 @Override 151 public boolean equals(Object obj) { 152 if (this == obj) { 153 return true; 154 } 155 if (obj instanceof AlternateUnit) { 156 AlternateUnit that = (AlternateUnit) obj; 157 return Objects.equals(parentUnit, that.parentUnit) && Objects.equals(getSymbol(), that.getSymbol()); 158 } 159 return false; 160 } 161 162 /** 163 * Creates an alternate unit for the specified system unit identified by the specified name and symbol. 164 * 165 * @param parent 166 * the system unit from which this alternate unit is derived. 167 * @param symbol 168 * the symbol for this alternate unit. 169 * @throws IllegalArgumentException 170 * if the specified parent unit is not an unscaled standard {@link AbstractUnit#isSystemUnit() system unit}. 171 * @throws MeasurementException 172 * if the specified symbol is not valid or is already associated to a different unit. 173 */ 174 public static <Q extends Quantity<Q>> AlternateUnit<Q> of(Unit<?> parent, String symbol) { 175 return new AlternateUnit<>(parent, symbol); 176 } 177 178 /** 179 * Creates an alternate unit for the specified system unit identified by the specified name and symbol. 180 * 181 * @param parent 182 * the system unit from which this alternate unit is derived. 183 * @param symbol 184 * the symbol for this alternate unit. 185 * @param name the name for this alternate unit. 186 * @throws IllegalArgumentException 187 * if the specified parent unit is not an unscaled standard {@link AbstractUnit#isSystemUnit() system unit}. 188 * @throws MeasurementException 189 * if the specified symbol is not valid or is already associated to a different unit. 190 * @since 2.0 191 */ 192 public static <Q extends Quantity<Q>> AlternateUnit<Q> of(Unit<?> parent, String symbol, String name) { 193 return new AlternateUnit<>(parent, symbol, name); 194 } 195}