--- /dev/null
+/**
+* Copyright (C) 2020 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.common;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Set;
+
+/**
+ * @author a.mueller
+ * @since 25.04.2020
+ */
+public final class BigDecimalUtil {
+
+ public static final BigDecimal MAX_BIGDECIMAL = BigDecimal.valueOf(Double.MAX_VALUE);
+
+ public static final BigDecimal MIN_BIGDECIMAL = BigDecimal.valueOf(Double.MIN_VALUE);
+
+ public static BigDecimal average(Set<BigDecimal> bigDecimals) {
+ BigDecimal sum = BigDecimal.ZERO;
+ int count=0;
+ for(BigDecimal bigDecimal : bigDecimals) {
+ if(null != bigDecimal) {
+ sum = sum.add(bigDecimal);
+ count++;
+ }
+ }
+ return sum.divide(new BigDecimal(count), RoundingMode.HALF_EVEN);
+ }
+}
--- /dev/null
+/**
+* Copyright (C) 2020 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.common.function;
+
+import java.math.BigDecimal;
+
+/**
+ * This is class is for testing how BigDecimal actually works
+ * and how float can be transformed to BigDecimal.
+ * Can be deleted.
+ *
+ * @author a.mueller
+ * @since 27.04.2020
+ */
+public class TestBigDecimal {
+
+ public static void main(String[] args) {
+ BigDecimal a = new BigDecimal(new Float(2.600f).toString());
+ System.out.println(a.toString());
+ System.out.println(a.toPlainString());
+ System.out.println(a.toEngineeringString());
+ String str = a.toString();
+ String strZero = "000";
+ String strNine = "999";
+ if (str.contains(strZero)){
+ int pos = str.indexOf(strZero);
+ String str2 = str.substring(0, pos);
+ BigDecimal b = new BigDecimal(str2);
+ System.out.println(b.toString());
+ }else if (str.contains(strNine)){
+ int pos = str.indexOf(strNine);
+ String str2 = str.substring(0, pos);
+ BigDecimal b = new BigDecimal(str2);
+ b = b.add(new BigDecimal(1).movePointLeft(b.scale()));
+ Float f = Float.parseFloat(b.toString());
+ System.out.println(b.toString());
+ System.out.println(f.toString());
+ }
+ }
+}
\r
import java.io.File;\r
import java.io.IOException;\r
+import java.math.BigDecimal;\r
import java.net.MalformedURLException;\r
import java.net.URI;\r
import java.net.URL;\r
if (value.contains(",")) {\r
value = value.replace(',', '.');\r
}\r
- Float v = Float.parseFloat(value);\r
+ BigDecimal v = new BigDecimal(value);\r
//Float v = new Float(0);\r
StatisticalMeasure t = null;\r
if (type.equals("Min")) {\r
import java.io.OutputStream;\r
import java.io.OutputStreamWriter;\r
import java.io.Writer;\r
+import java.math.BigDecimal;\r
import java.util.HashMap;\r
import java.util.HashSet;\r
import java.util.Iterator;\r
} else {\r
measure.setAttribute("type", label);\r
}\r
- float value = statisticalValue.getValue();\r
+ BigDecimal value = statisticalValue.getValue();\r
measure.setAttribute("value", String.valueOf(value));\r
element.appendChild(measure);\r
}\r
import java.io.File;
import java.io.FileNotFoundException;
+import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
description.addElement(catData);
//QuantitativeData
- QuantitativeData quantData = QuantitativeData.NewMinMaxInstance(Feature.CHROMOSOME_NUMBER(), 0.1f, 1.3f);
- quantData.setSampleSize(2f, null);
+ QuantitativeData quantData = QuantitativeData.NewMinMaxInstance(Feature.CHROMOSOME_NUMBER(), new BigDecimal("0.1"), new BigDecimal("1.3"));
+ quantData.setSampleSize(new BigDecimal("2"), null);
setUuid(quantData,"011264eb-d3d4-44be-86f3-e6f69a21f36b");
description.addElement(quantData);
*/
package eu.etaxonomy.cdm.format.description;
+import java.math.BigDecimal;
+
import eu.etaxonomy.cdm.common.CdmUtils;
import eu.etaxonomy.cdm.model.description.MeasurementUnit;
import eu.etaxonomy.cdm.model.description.QuantitativeData;
String result = "";
//values
- Float min = quantData.getMin();
- Float max = quantData.getMax();
+ BigDecimal min = quantData.getMin();
+ BigDecimal max = quantData.getMax();
String minMax = "";
if (min != null){
minMax = String.valueOf(min);
minMax = "<" + String.valueOf(max);
}
String exactValueStr = "";
- for(Float exactValue : quantData.getExactValues()){
+ for(BigDecimal exactValue : quantData.getExactValues()){
if (exactValue != null){
exactValueStr += CdmUtils.concat(";", exactValueStr, String.valueOf(exactValue));
}
result = CdmUtils.concat(" ", result, unitStr);
//bracket
- Float n = quantData.getSampleSize();
+ BigDecimal n = quantData.getSampleSize();
String size = (n == null) ? "" : "n="+String.valueOf(n);
String strBracket = isNotBlank(size) ? "[" + size + "]" : "";
\r
import org.hibernate.HibernateException;\r
import org.hibernate.engine.spi.SessionImplementor;\r
+import org.hibernate.type.BigDecimalType;\r
import org.hibernate.type.StandardBasicTypes;\r
import org.hibernate.usertype.UserType;\r
\r
/**\r
- * This software is public domain and carries NO WARRANTY.\r
+ * Hibernate {@link UserType} for BigDecimal with correct handling for scale.\r
+ * Correct means that a BigDecimal with scale 2 will be stored and reloaded\r
+ * with scale 2 even if the defined scale in the database has a higher scale defined.\r
*\r
- * Patches, bug reports and feature requests welcome:\r
+ * E.g. "1.32" is persisted as exactly this BigDecimal even if scale of the column is\r
+ * defined with scale = 4. The default {@link BigDecimalType} stores and reloads it\r
+ * as 1.3200 which is a difference when handling e.g. measurement values as it looses the\r
+ * information about the exactness of the data.<BR><BR>\r
*\r
- * https://bitbucket.org/ratkins/bigdecimalusertype/\r
+ * Usage example with annotations (with type already declared in according package-info.java):<BR>\r
+ *\r
+ * <BR>@Columns(columns={@Column(name="xxx", precision = 18, scale = 9), @Column(name="xxx_scale")})\r
+ * <BR>@Type(type="bigDecimalUserType")\r
+ * <BR><BR>\r
+ *\r
+ * This class has been originally copied and adapted from\r
+ * https://bitbucket.org/ratkins/bigdecimalusertype/src/default/<BR><BR>\r
*/\r
public class BigDecimalUserType implements UserType {\r
\r
- private static final int[] SQL_TYPES = new int[] {Types.DECIMAL, Types.INTEGER};\r
+ private static final int[] SQL_TYPES = new int[] {\r
+ Types.NUMERIC, //for some reason Types.Decimal does not exist at least in MySQL Dialect\r
+ Types.INTEGER};\r
\r
@Override\r
public Object assemble(Serializable arg0, Object arg1) throws HibernateException {\r
@org.hibernate.annotations.TypeDef(name="doiUserType", typeClass=eu.etaxonomy.cdm.hibernate.DOIUserType.class),
@org.hibernate.annotations.TypeDef(name="orcidUserType", typeClass=eu.etaxonomy.cdm.hibernate.OrcidUserType.class),
@org.hibernate.annotations.TypeDef(name="shiftUserType", typeClass=eu.etaxonomy.cdm.hibernate.ShiftUserType.class),
+ @org.hibernate.annotations.TypeDef(name="bigDecimalUserType", typeClass=eu.etaxonomy.cdm.hibernate.BigDecimalUserType.class),
})
@org.hibernate.annotations.AnyMetaDef(name = "CdmBase" ,
metaType="string",
package eu.etaxonomy.cdm.model.description;
+import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.validator.constraints.NotEmpty;
+import eu.etaxonomy.cdm.common.BigDecimalUtil;
import eu.etaxonomy.cdm.model.term.DefinedTerm;
import eu.etaxonomy.cdm.validation.Level2;
@Entity
@Indexed(index = "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
@Audited
-public class QuantitativeData extends DescriptionElementBase implements Cloneable {
- private static final long serialVersionUID = -2755806455420051488L;
+public class QuantitativeData
+ extends DescriptionElementBase {
+ private static final long serialVersionUID = -2755806455420051488L;
private static final Logger logger = Logger.getLogger(QuantitativeData.class);
@XmlElement(name = "MeasurementUnit")
/**
* Creates a new quantitative data instance of type feature with defined min and may value.
*/
- public static QuantitativeData NewMinMaxInstance(Feature feature, float min, float max){
+ public static QuantitativeData NewMinMaxInstance(Feature feature, BigDecimal min, BigDecimal max){
QuantitativeData result = new QuantitativeData(feature);
StatisticalMeasurementValue minValue = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.MIN(),min);
result.addStatisticalValue(minValue);
/**
* Creates a new quantitative data instance of type feature with defined exact value.
*/
- public static QuantitativeData NewExactValueInstance(Feature feature, float... exactValues){
+ public static QuantitativeData NewExactValueInstance(Feature feature, BigDecimal... exactValues){
QuantitativeData result = new QuantitativeData(feature);
- for (float exactVal : exactValues){
+ for (BigDecimal exactVal : exactValues){
StatisticalMeasurementValue exactValue = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.EXACT_VALUE(), exactVal);
result.addStatisticalValue(exactValue);
}
// ******************************** TRANSIENT METHODS *******************************/
@Transient
- public Float getOverallMin(){
- float result = Float.MAX_VALUE;
+ public BigDecimal getOverallMin(){
+ BigDecimal result = BigDecimalUtil.MAX_BIGDECIMAL;
for (StatisticalMeasurementValue value : statisticalValues){
if (withRangeValue(value)){
- result = Math.min(result, value.getValue());;
+ result = result.min(value.getValue());
}
}
- return (result == Float.MAX_VALUE)? null: result;
+ return (result == BigDecimalUtil.MAX_BIGDECIMAL)? null: result;
}
@Transient
- public Float getOverallMax(){
- float result = Float.MIN_VALUE;
+ public BigDecimal getOverallMax(){
+ BigDecimal result = BigDecimalUtil.MIN_BIGDECIMAL;
for (StatisticalMeasurementValue value : statisticalValues){
if (withRangeValue(value)){
- result = Math.max(result, value.getValue());;
+ result = result.max(value.getValue());
}
}
- return (result == Float.MIN_VALUE)? null: result;
+ return (result == BigDecimalUtil.MIN_BIGDECIMAL)? null: result;
}
private boolean withRangeValue(StatisticalMeasurementValue value) {
* statistical measurement value instance exists.
*/
@Transient
- public Float getMin(){
+ public BigDecimal getMin(){
return getSpecificStatisticalValue(StatisticalMeasure.MIN());
}
* statistical measurement value instance exists.
*/
@Transient
- public Float getMax(){
+ public BigDecimal getMax(){
return getSpecificStatisticalValue(StatisticalMeasure.MAX());
}
* Returns <code>null</code> if no such statistical measurement value instance exists.
*/
@Transient
- public Float getTypicalLowerBoundary(){
+ public BigDecimal getTypicalLowerBoundary(){
return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
}
@Transient
- public Set<Float> getExactValues(){
+ public Set<BigDecimal> getExactValues(){
return getSpecificStatisticalValues(StatisticalMeasure.EXACT_VALUE());
}
* Returns <code>null</code> if no such statistical measurement value instance exists.
*/
@Transient
- public Float getAverage(){
+ public BigDecimal getAverage(){
return getSpecificStatisticalValue(StatisticalMeasure.AVERAGE());
}
* Returns <code>null</code> if no such statistical measurement value instance exists.
*/
@Transient
- public Float getStandardDeviation(){
+ public BigDecimal getStandardDeviation(){
return getSpecificStatisticalValue(StatisticalMeasure.STANDARD_DEVIATION());
}
* Returns <code>null</code> if no such statistical measurement value instance exists.
*/
@Transient
- public Float getSampleSize(){
+ public BigDecimal getSampleSize(){
return getSpecificStatisticalValue(StatisticalMeasure.SAMPLE_SIZE());
}
* Returns <code>null</code> if no such statistical measurement value instance exists.
*/
@Transient
- public Float getTypicalUpperBoundary(){
+ public BigDecimal getTypicalUpperBoundary(){
return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
}
* @param type
* @return the value
*/
- public Float getSpecificStatisticalValue(StatisticalMeasure type){
- Float result = null;
+ public BigDecimal getSpecificStatisticalValue(StatisticalMeasure type){
+ BigDecimal result = null;
for (StatisticalMeasurementValue value : statisticalValues){
if (type.equals(value.getType())){
result = value.getValue();
return result;
}
- public Set<Float> getSpecificStatisticalValues(StatisticalMeasure type){
- Set<Float> result = new HashSet<>();
+ public Set<BigDecimal> getSpecificStatisticalValues(StatisticalMeasure type){
+ Set<BigDecimal> result = new HashSet<>();
for (StatisticalMeasurementValue value : statisticalValues){
if (type.equals(value.getType())){
result.add(value.getValue());
* @return the newValue
*/
@Transient
- public StatisticalMeasurementValue setMinimum(Float value, Set<DefinedTerm> modifiers){
+ public StatisticalMeasurementValue setMinimum(BigDecimal value, Set<DefinedTerm> modifiers){
return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.MIN());
}
* @return the newValue
*/
@Transient
- public StatisticalMeasurementValue setMaximum(Float value, Set<DefinedTerm> modifiers){
+ public StatisticalMeasurementValue setMaximum(BigDecimal value, Set<DefinedTerm> modifiers){
return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.MAX());
}
* @return the newValue
*/
@Transient
- public StatisticalMeasurementValue setAverage(Float value, Set<DefinedTerm> modifiers){
+ public StatisticalMeasurementValue setAverage(BigDecimal value, Set<DefinedTerm> modifiers){
return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.AVERAGE());
}
-
/**
* Sets the statistical value for the standard deviation.
* If such value exists the old value is replaced by the new value.
* @return the newValue
*/
@Transient
- public StatisticalMeasurementValue setStandardDeviation(Float value, Set<DefinedTerm> modifiers){
+ public StatisticalMeasurementValue setStandardDeviation(BigDecimal value, Set<DefinedTerm> modifiers){
return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.STANDARD_DEVIATION());
}
* @return the newValue
*/
@Transient
- public StatisticalMeasurementValue setSampleSize(Float value, Set<DefinedTerm> modifiers){
+ public StatisticalMeasurementValue setSampleSize(BigDecimal value, Set<DefinedTerm> modifiers){
return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.SAMPLE_SIZE());
}
* @return the newValue
*/
@Transient
- public StatisticalMeasurementValue setTypicalLowerBoundary(Float value, Set<DefinedTerm> modifiers){
+ public StatisticalMeasurementValue setTypicalLowerBoundary(BigDecimal value, Set<DefinedTerm> modifiers){
return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
}
* @return the newValue
*/
@Transient
- public StatisticalMeasurementValue setTypicalUpperBoundary(Float value, Set<DefinedTerm> modifiers){
+ public StatisticalMeasurementValue setTypicalUpperBoundary(BigDecimal value, Set<DefinedTerm> modifiers){
return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
}
* @param value
* @return the newValue
*/
- public StatisticalMeasurementValue setSpecificStatisticalValue(Float value, Set<DefinedTerm> modifiers, StatisticalMeasure type){
+ public StatisticalMeasurementValue setSpecificStatisticalValue(BigDecimal value,
+ Set<DefinedTerm> modifiers, StatisticalMeasure type){
StatisticalMeasurementValue result = null;
StatisticalMeasurementValue existingSmValue = null;
package eu.etaxonomy.cdm.model.description;\r
\r
\r
+import java.math.BigDecimal;\r
import java.util.HashSet;\r
import java.util.Set;\r
\r
+import javax.persistence.Column;\r
import javax.persistence.Entity;\r
import javax.persistence.FetchType;\r
import javax.persistence.ManyToMany;\r
import javax.persistence.ManyToOne;\r
+import javax.validation.constraints.NotNull;\r
import javax.xml.bind.annotation.XmlAccessType;\r
import javax.xml.bind.annotation.XmlAccessorType;\r
import javax.xml.bind.annotation.XmlElement;\r
import javax.xml.bind.annotation.XmlType;\r
\r
import org.apache.log4j.Logger;\r
+import org.hibernate.annotations.Columns;\r
+import org.hibernate.annotations.Type;\r
import org.hibernate.envers.Audited;\r
import org.hibernate.search.annotations.Indexed;\r
import org.hibernate.search.annotations.IndexedEmbedded;\r
private static final long serialVersionUID = -3576311887760351982L;\r
private static final Logger logger = Logger.getLogger(StatisticalMeasurementValue.class);\r
\r
- @XmlElement(name = "Value")\r
- private float value;\r
+ @XmlElement(name = "Value")\r
+ @Columns(columns={@Column(name="value", precision = 18, scale = 9), @Column(name="value_scale")})\r
+ @Type(type="bigDecimalUserType")\r
+ @NotNull //#8978 the old float value also could not be null and a value without value does not make sense, but do we want to have a default?\r
+ private BigDecimal value;\r
\r
@XmlElementWrapper(name = "Modifiers")\r
@XmlElement(name = "Modifier")\r
@IndexedEmbedded(depth=1)\r
private QuantitativeData quantitativeData;\r
\r
+// ***************** FACTORY ****************************/\r
\r
+ public static StatisticalMeasurementValue NewInstance(){\r
+ return new StatisticalMeasurementValue();\r
+ }\r
+\r
+ public static StatisticalMeasurementValue NewInstance(StatisticalMeasure type, BigDecimal value){\r
+ StatisticalMeasurementValue result = new StatisticalMeasurementValue();\r
+ result.setValue(value);\r
+ result.setType(type);\r
+ return result;\r
+ }\r
+\r
+// ******************* CONSTRUCTOR *************************/\r
\r
protected StatisticalMeasurementValue(){\r
super();\r
}\r
\r
- /**\r
- * Creates a new empty statistical measurement value instance.\r
- */\r
- public static StatisticalMeasurementValue NewInstance(){\r
- return new StatisticalMeasurementValue();\r
- }\r
-\r
-\r
- /**\r
- * Creates a new empty statistical measurement value instance.\r
- */\r
- public static StatisticalMeasurementValue NewInstance(StatisticalMeasure type, float value){\r
- StatisticalMeasurementValue result = new StatisticalMeasurementValue();\r
- result.setValue(value);\r
- result.setType(type);\r
- return result;\r
- }\r
+// ***************** GETTER / SETTER **************************/\r
\r
\r
/**\r
* corresponding to the {@link QuantitativeData quantitative data} <i>this</i>\r
* statistical measurement value belongs to.\r
*/\r
- public float getValue(){\r
+ public BigDecimal getValue(){\r
return this.value;\r
}\r
/**\r
* @see #getValue()\r
*/\r
- public void setValue(float value){\r
+ public void setValue(BigDecimal value){\r
this.value = value;\r
}\r
\r
private static final long serialVersionUID = 531030660792800636L;
private static final Logger logger = Logger.getLogger(Point.class);
- //TODO was Float but H2 threw errors
+ //TODO was Float but H2 threw errors, maybe we should also use BigDecimal for exactness, see #8978
@XmlElement(name = "Longitude")
@Longitude(of="point")
@NotNull(groups = Level2.class)
package eu.etaxonomy.cdm.strategy.generate;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import org.apache.log4j.Logger;
+import eu.etaxonomy.cdm.common.BigDecimalUtil;
import eu.etaxonomy.cdm.model.common.CdmBase;
import eu.etaxonomy.cdm.model.common.Language;
import eu.etaxonomy.cdm.model.description.CategoricalData;
logger.warn("Only 1 or no taxon covered. This should currently only be possible on top level and is not yet handled. ");
}else {
// this map stores the thresholds giving the best dichotomy of taxa for the corresponding feature supporting quantitative data
- Map<Feature,Float> quantitativeFeaturesThresholds = new HashMap<>();
+ Map<Feature,BigDecimal> quantitativeFeaturesThresholds = new HashMap<>();
// the scores of the different features are calculated, the thresholds in the same time
if (config.isDebug()){
System.out.println("Feature left: " + featuresLeft + ", taxa: " + taxaCovered);
}else if (feature.isSupportsQuantitativeData()){
Iterator<KeyTaxon> it = candidates.iterator();
while (it.hasNext()){
- float min = Float.MAX_VALUE;
- Float max = Float.MIN_VALUE;
+ BigDecimal min = BigDecimalUtil.MAX_BIGDECIMAL;
+ BigDecimal max = BigDecimalUtil.MIN_BIGDECIMAL;
Set<QuantitativeData> qds = it.next().quantitativeData.get(feature);
qds = qds == null? new HashSet<>(): qds;
for (QuantitativeData qd : qds){
- Float qdMin = qd.getOverallMin();
+ BigDecimal qdMin = qd.getOverallMin();
if(qdMin != null){
- min = Math.min(min, qdMin);
+ min = min.min(qdMin);
}
- Float qdMax = qd.getOverallMax();
+ BigDecimal qdMax = qd.getOverallMax();
if(qdMax != null){
- max = Math.max(max, qdMax);
+ max = max.max(qdMax);
}
}
boolean staysCandidate = true;
Set<QuantitativeData> tqds = taxon.quantitativeData.get(feature);
tqds = tqds == null? new HashSet<>(): tqds;
for (QuantitativeData qd : tqds){
- staysCandidate &= qd.getOverallMin() == null || qd.getOverallMin() >= min;
- staysCandidate &= qd.getOverallMax() == null || qd.getOverallMax() <= max;
+ staysCandidate &= qd.getOverallMin() == null || qd.getOverallMin().compareTo(min) >= 0;
+ staysCandidate &= qd.getOverallMax() == null || qd.getOverallMax().compareTo(max) <= 0;
}
if (!staysCandidate){
break;
}
private void handleQuantitativeData(PolytomousKeyNode parent, List<Feature> featuresLeft,
- Set<KeyTaxon> taxaCovered, Map<Feature, Float> quantitativeFeaturesThresholds,
+ Set<KeyTaxon> taxaCovered, Map<Feature, BigDecimal> quantitativeFeaturesThresholds,
Feature winnerFeature, Map<Feature, Set<State>> featureStatesFilter) {
// first, get the threshold
- float threshold = quantitativeFeaturesThresholds.get(winnerFeature);
+ BigDecimal threshold = quantitativeFeaturesThresholds.get(winnerFeature);
//TODO unit not seems to be used yet
StringBuilder unit = new StringBuilder();
// then determine which taxa are before and which are after this threshold (dichotomy)
* TODO if the quantitative feature has dependent features they are not yet handled
*/
private void handleQuantitativeBranch(PolytomousKeyNode parent, List<Feature> featuresLeft,
- int parentTaxaCoveredSize, Feature winnerFeature, float threshold, StringBuilder unit,
+ int parentTaxaCoveredSize, Feature winnerFeature, BigDecimal threshold, StringBuilder unit,
List<Set<KeyTaxon>> quantitativeStates, Map<Feature, Set<State>> featureStatesFilter,
int brunchNum) {
}
private Feature computeScores(List<Feature> featuresLeft, Set<KeyTaxon> taxaCovered,
- Map<Feature, Float> quantitativeFeaturesThresholds, Map<Feature, Set<State>> featureStatesFilter) {
+ Map<Feature,BigDecimal> quantitativeFeaturesThresholds, Map<Feature, Set<State>> featureStatesFilter) {
Map<Feature,Float> scoreMap = featureScores(featuresLeft, taxaCovered, quantitativeFeaturesThresholds, featureStatesFilter);
dependenciesScores(scoreMap, featuresLeft, taxaCovered, quantitativeFeaturesThresholds, featureStatesFilter);
* "onlyApplicableIf" or "InapplicableIf", the feature it depends can be chosen in order to build a better key.
*/
private void dependenciesScores(Map<Feature,Float> scoreMap, List<Feature> featuresLeft,
- Set<KeyTaxon> coveredTaxa, Map<Feature,Float> quantitativeFeaturesThresholds, Map<Feature, Set<State>> featureStatesFilter){
+ Set<KeyTaxon> coveredTaxa, Map<Feature,BigDecimal> quantitativeFeaturesThresholds, Map<Feature, Set<State>> featureStatesFilter){
//TODO maybe we need to do this recursive?
* This function fills the map of features (keys) with their respecting scores (values)
*/
private Map<Feature,Float> featureScores(List<Feature> featuresLeft, Set<KeyTaxon> coveredTaxa,
- Map<Feature,Float> quantitativeFeaturesThresholds, Map<Feature, Set<State>> featureStatesFilter){
+ Map<Feature,BigDecimal> quantitativeFeaturesThresholds, Map<Feature, Set<State>> featureStatesFilter){
Map<Feature,Float> scoreMap = new HashMap<>();
for (Feature feature : featuresLeft){
* It returns two Sets of {@link KeyTaxon}, one with the taxa under this threshold (taxaBefore) and another one
* with the taxa over (taxaAfter).
*/
- private List<Set<KeyTaxon>> determineQuantitativeStates (Float threshold, Feature feature,
+ private List<Set<KeyTaxon>> determineQuantitativeStates (BigDecimal threshold, Feature feature,
Set<KeyTaxon> taxa, StringBuilder unit){
List<Set<KeyTaxon>> list = new ArrayList<>();
StatisticalMeasure type = smv.getType();
//TODO DONT FORGET sample size, MEAN etc
if (type.isMax() || type.isTypicalUpperBoundary() || type.isAverage() || type.isExactValue()) {
- if (smv.getValue()>threshold){
+ if (smv.getValue().compareTo(threshold) > 0){
taxaAfter.add(td);
}
}
if (type.isMin() || type.isTypicalLowerBoundary() || type.isAverage() || type.isExactValue()) {
- if (smv.getValue()<=threshold){
+ if (smv.getValue().compareTo(threshold) <= 0){
taxaBefore.add(td);
}
}
/**
* This function returns the score of a quantitative feature.
*/
- private float quantitativeFeatureScore(Feature feature, Set<KeyTaxon> coveredTaxa, Map<Feature,Float> quantitativeFeaturesThresholds){
+ private float quantitativeFeatureScore(Feature feature, Set<KeyTaxon> coveredTaxa,
+ Map<Feature,BigDecimal> quantitativeFeaturesThresholds){
- List<Float> allValues = new ArrayList<>();
+ List<BigDecimal> allValues = new ArrayList<>();
for (KeyTaxon td : coveredTaxa){
for (QuantitativeData qd : td.getQuantitativeData(feature)){
computeAllValues(allValues, qd);
}
}
int i,j;
- float threshold=0;
- float bestThreshold=0;
- int difference=allValues.size();
+ BigDecimal threshold = BigDecimal.ZERO;
+ BigDecimal bestThreshold = BigDecimal.ZERO;
+ int difference = allValues.size();
int differenceMin = difference;
- int bestTaxaBefore=0;
- int bestTaxaAfter=0;
- for (i=0;i<allValues.size()/2;i++) {
+ int bestTaxaBefore = 0;
+ int bestTaxaAfter = 0;
+ for (i=0; i<allValues.size()/2; i++) {
threshold = allValues.get(i*2+1);
int taxaBefore=0;
int taxaAfter=0;
for (j=0;j<allValues.size()/2;j++) {
- if (allValues.get(j*2+1)<=threshold){
+ if (allValues.get(j*2+1).compareTo(threshold) <= 0){
taxaBefore++;
}
- if (allValues.get(j*2)>threshold){
+ if (allValues.get(j*2).compareTo(threshold) > 0){
taxaAfter++;
}
}
return defaultQuantitativeScore;
}
- private void computeAllValues(List<Float> allValues, QuantitativeData qd) {
+ private void computeAllValues(List<BigDecimal> allValues, QuantitativeData qd) {
Set<StatisticalMeasurementValue> values = qd.getStatisticalValues();
- Float lowerboundary=null;
- Float upperboundary=null;
+ BigDecimal lowerboundary = null;
+ BigDecimal upperboundary = null;
for (StatisticalMeasurementValue smv : values){
StatisticalMeasure type = smv.getType();
- float value = smv.getValue();
+ BigDecimal value = smv.getValue();
// DONT FORGET sample size, MEAN etc
if(type.isMin() || type.isTypicalLowerBoundary() || type.isAverage() || type.isExactValue()){
if (lowerboundary == null){
lowerboundary = value;
}else{
- lowerboundary = Math.min(lowerboundary, value);
+ lowerboundary = lowerboundary.min(value);
}
}
if(type.isMax() || type.isTypicalUpperBoundary() || type.isAverage() || type.isExactValue()){
if (upperboundary == null){
upperboundary = value;
}else{
- upperboundary = Math.max(upperboundary, value);
+ upperboundary = upperboundary.max(value);
}
}
*/
package eu.etaxonomy.cdm.format;
+import java.math.BigDecimal;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
@Before
public void setUp() throws Exception {
- min1 = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.MIN(), 0.1f);
- max1 = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.MAX(), 1.3f);
- n1 = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.SAMPLE_SIZE(), 2);
+ min1 = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.MIN(), new BigDecimal("0.1"));
+ max1 = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.MAX(), new BigDecimal("1.3"));
+ n1 = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.SAMPLE_SIZE(), new BigDecimal("2"));
}
@BeforeClass
quantData.setUnit(unit);
text = formatter.format(quantData, formatKey);
- Assert.assertEquals("0.1-1.3 m [n=2.0]", text);
-
+ Assert.assertEquals("0.1-1.3 m [n=2]", text);
}
-
}
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
+import java.math.BigDecimal;
+
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
StatisticalMeasurementValue statisticalValue = StatisticalMeasurementValue.NewInstance();
statisticalValue.setType(StatisticalMeasure.AVERAGE() );
- statisticalValue.setValue((float) 23.8);
+ statisticalValue.setValue(new BigDecimal("23.8"));
quantData.addStatisticalValue(statisticalValue);
}
@Test
public void testClone(){
QuantitativeData clone = (QuantitativeData) quantData.clone();
- float cloneValue = clone.getStatisticalValues().iterator().next().getValue();
- float origValue = quantData.getStatisticalValues().iterator().next().getValue();
+ BigDecimal cloneValue = clone.getStatisticalValues().iterator().next().getValue();
+ BigDecimal origValue = quantData.getStatisticalValues().iterator().next().getValue();
assertTrue(origValue == cloneValue);
assertNotSame(clone.getStatisticalValues().iterator().next(), quantData.getStatisticalValues().iterator().next());
}
import static org.junit.Assert.assertNotNull;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
private static final boolean debug = true;
private static final String GT_3 = " > 3.0";
- private static final String GT_3_5 = " > 3.5";
+// private static final String GT_3_5 = " > 3.5";
private static final String LESS_3 = " < 3.0";
- private static final String LESS_3_5 = " < 3.5";
+// private static final String LESS_3_5 = " < 3.5";
private static final boolean QUANTITATIVE = true;
private static final boolean CATEGORICAL = false;
//*************************/
- qtd31 = QuantitativeData.NewExactValueInstance(featureLength, 0.0f, 3.0f);
+ qtd31 = QuantitativeData.NewExactValueInstance(featureLength, new BigDecimal("0.0"), new BigDecimal("3.0"));
// qtd31 = QuantitativeData.NewMinMaxInstance(featureLength, 0, 3);
- qtd32 = QuantitativeData.NewMinMaxInstance(featureLength, 0, 3);
- qtd33 = QuantitativeData.NewMinMaxInstance(featureLength, 6, 9);
- qtd34 = QuantitativeData.NewMinMaxInstance(featureLength, 6, 9);
- qtd35 = QuantitativeData.NewMinMaxInstance(featureLength, 0, 3);
- qtd36 = QuantitativeData.NewMinMaxInstance(featureLength, 0, 3);
- qtd37 = QuantitativeData.NewMinMaxInstance(featureLength, 6, 9);
- qtd38 = QuantitativeData.NewMinMaxInstance(featureLength, 0, 3);
+ qtd32 = QuantitativeData.NewMinMaxInstance(featureLength, new BigDecimal("0.0"), new BigDecimal("3.0"));
+ qtd33 = QuantitativeData.NewMinMaxInstance(featureLength, new BigDecimal("6.0"), new BigDecimal("9.0"));
+ qtd34 = QuantitativeData.NewMinMaxInstance(featureLength, new BigDecimal("6.0"), new BigDecimal("9.0"));
+ qtd35 = QuantitativeData.NewMinMaxInstance(featureLength, new BigDecimal("0.0"), new BigDecimal("3.0"));
+ qtd36 = QuantitativeData.NewMinMaxInstance(featureLength, new BigDecimal("0.0"), new BigDecimal("3.0"));
+ qtd37 = QuantitativeData.NewMinMaxInstance(featureLength, new BigDecimal("6.0"), new BigDecimal("9.0"));
+ qtd38 = QuantitativeData.NewMinMaxInstance(featureLength, new BigDecimal("0.0"), new BigDecimal("3.0"));
//*************************/
*/
package eu.etaxonomy.cdm.database.data;
+import java.math.BigDecimal;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
MeasurementUnit measurementUnit = MeasurementUnit.NewInstance("Measurement Unit", "munit", null);
cdmBases.add(measurementUnit);
quantitativeData.setUnit(measurementUnit);
- StatisticalMeasurementValue statisticalMeasurementValue = quantitativeData.setAverage((float)22.9 , null);
+ quantitativeData.setUuid(UUID.fromString("920fce5e-4913-4a3f-89bf-1611f5081869"));
+ StatisticalMeasurementValue statisticalMeasurementValue = quantitativeData.setAverage(
+ new BigDecimal("22.9215"), null);
handleAnnotatableEntity(quantitativeData);
handleIdentifiableEntity(measurementUnit);
DefinedTerm valueModifier = DefinedTerm.NewModifierInstance("about", "about", null);
\r
private final String newColumnName;\r
private final Datatype columnType;\r
- private Integer size;\r
+ private final Integer size;\r
+ private final Integer scale;\r
private final Object defaultValue;\r
private boolean isNotNull;\r
private final String referencedTable;\r
* @return\r
*/\r
public static final ColumnAdder NewIntegerInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull, String referencedTable){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.INTEGER, null, includeAudTable, null, notNull, referencedTable);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.INTEGER, null, null, includeAudTable, null, notNull, referencedTable);\r
}\r
\r
public static final ColumnAdder NewIntegerInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, Integer defaultValue, boolean notNull){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.INTEGER, null, includeAudTable, defaultValue, notNull, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.INTEGER, null, null, includeAudTable, defaultValue, notNull, null);\r
}\r
\r
public static final ColumnAdder NewTinyIntegerInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.TINYINTEGER, null, includeAudTable, null, notNull, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.TINYINTEGER, null, null, includeAudTable, null, notNull, null);\r
}\r
\r
public static final ColumnAdder NewDoubleInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.DOUBLE, null, includeAudTable, null, notNull, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.DOUBLE, null, null, includeAudTable, null, notNull, null);\r
}\r
\r
+ public static final ColumnAdder NewDecimalInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, int precision, int scale, boolean includeAudTable, Integer defaultValue, boolean notNull){\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.BIGDECIMAL, precision, scale, includeAudTable, defaultValue, notNull, null);\r
+ }\r
+\r
public static final ColumnAdder NewBooleanInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, Boolean defaultValue){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.BIT, null, includeAudTable, defaultValue, false, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.BIT, null, null, includeAudTable, defaultValue, false, null);\r
}\r
\r
/**\r
* Adds a string column with length 255 and default value <code>null</code>\r
*/\r
public static final ColumnAdder NewStringInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.VARCHAR, 255, includeAudTable, null, false, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.VARCHAR, 255, null, includeAudTable, null, false, null);\r
}\r
\r
public static final ColumnAdder NewDTYPEInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String defaultValue, boolean includeAudTable){\r
- return new ColumnAdder(stepList, stepName, tableName, "DTYPE", Datatype.VARCHAR, 31, includeAudTable, defaultValue, true, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, "DTYPE", Datatype.VARCHAR, 31, null, includeAudTable, defaultValue, true, null);\r
}\r
\r
/**\r
* Adds a string column with the given length and default value <code>null</code>\r
*/\r
public static final ColumnAdder NewStringInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, int length, boolean includeAudTable){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.VARCHAR, length, includeAudTable, null, false, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.VARCHAR, length, null, includeAudTable, null, false, null);\r
}\r
\r
/**\r
* Adds a string column with the given length and the given default value\r
*/\r
public static final ColumnAdder NewStringInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, int length, String defaultValue, boolean includeAudTable){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.VARCHAR, length, includeAudTable, defaultValue, false, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.VARCHAR, length, null, includeAudTable, defaultValue, false, null);\r
}\r
\r
public static final ColumnAdder NewClobInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.CLOB, null, includeAudTable, null, false, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.CLOB, null, null, includeAudTable, null, false, null);\r
}\r
\r
public static final ColumnAdder NewDateTimeInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){\r
- return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.DATETIME, null, includeAudTable, null, notNull, null);\r
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.DATETIME, null, null, includeAudTable, null, notNull, null);\r
}\r
\r
- protected ColumnAdder(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, Datatype columnType, Integer size, boolean includeAudTable, Object defaultValue, boolean notNull, String referencedTable) {\r
+ protected ColumnAdder(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName,\r
+ Datatype columnType, Integer size, Integer scale, boolean includeAudTable, Object defaultValue, boolean notNull, String referencedTable) {\r
super(stepList, stepName, tableName, includeAudTable);\r
this.newColumnName = newColumnName;\r
this.columnType = columnType;\r
this.defaultValue = defaultValue;\r
this.isNotNull = notNull;\r
this.referencedTable = referencedTable;\r
+ this.scale = scale;\r
}\r
\r
public ColumnAdder setNotNull(boolean isNotNull) {\r
public String getUpdateQueryString(String tableName, ICdmDataSource datasource, IProgressMonitor monitor) throws DatabaseTypeNotSupportedException {\r
String updateQuery;\r
DatabaseTypeEnum type = datasource.getDatabaseType();\r
- String databaseColumnType = this.columnType.format(datasource, size);\r
+ String databaseColumnType = this.columnType.format(datasource, size, scale);\r
\r
if (type.equals(DatabaseTypeEnum.SqlServer2005)){\r
//MySQL allows both syntaxes\r
return new ColumnNameChanger(stepList, stepName, tableName, oldColumnName, newColumnName, includeAudTable, null, Datatype.INTEGER, null);\r
}\r
\r
+ public static ColumnNameChanger NewFloatInstance(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String oldColumnName, String newColumnName, boolean includeAudTable){\r
+ return new ColumnNameChanger(stepList, stepName, tableName, oldColumnName, newColumnName, includeAudTable, null, Datatype.FLOAT, null);\r
+ }\r
+\r
public static ColumnNameChanger NewClobInstance(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String oldColumnName,\r
String newColumnName, boolean includeAudTable){\r
return new ColumnNameChanger(stepList, stepName, tableName, oldColumnName, newColumnName, includeAudTable, null, Datatype.CLOB, null);\r
private final String columnName;\r
private final Datatype newColumnType;\r
private final Integer newSize;\r
+ private final Integer newScale;\r
private final Object defaultValue;\r
private final boolean isNotNull;\r
private final String referencedTable;\r
+ private final boolean isBigDecimal;\r
+ private String secondColumnName;\r
\r
\r
public static final ColumnTypeChanger NewStringSizeInstance(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String columnName, int newSize, boolean includeAudTable){\r
- return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.VARCHAR, newSize, includeAudTable, null, false, null);\r
+ return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.VARCHAR, newSize, null, includeAudTable, null, false, null, false, null);\r
}\r
\r
public static final ColumnTypeChanger NewClobInstance(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String columnName, boolean includeAudTable){\r
- return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.CLOB, null, includeAudTable, null, false, null);\r
+ return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.CLOB, null, null, includeAudTable, null, false, null, false, null);\r
}\r
\r
public static final ColumnTypeChanger NewInt2DoubleInstance(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String columnName, boolean includeAudTable){\r
- return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.DOUBLE, null, includeAudTable, null, false, null);\r
+ return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.DOUBLE, null, null, includeAudTable, null, false, null, false, null);\r
}\r
\r
public static final ColumnTypeChanger NewInt2StringInstance(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String columnName, int size, boolean includeAudTable, Integer defaultValue, boolean notNull){\r
- return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.VARCHAR, size, includeAudTable, defaultValue, notNull, null);\r
+ return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.VARCHAR, size, null, includeAudTable, defaultValue, notNull, null, false, null);\r
}\r
\r
public static final ColumnTypeChanger NewChangeAllowNullOnIntChanger(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String columnName, boolean includeAudTable){\r
- return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.INTEGER, null, includeAudTable, null, false, null);\r
+ return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.INTEGER, null, null, includeAudTable, null, false, null, false, null);\r
}\r
\r
public static final ColumnTypeChanger NewChangeAllowNullOnStringChanger(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String columnName, Integer size, boolean includeAudTable){\r
- return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.VARCHAR, size, includeAudTable, null, false, null);\r
+ return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.VARCHAR, size, null, includeAudTable, null, false, null, false, null);\r
}\r
\r
+ public static final ColumnTypeChanger NewFloat2BigDecimalInstance(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String columnName, String newSecondColumnName, int newPrecision, int newScale, boolean includeAudTable){\r
+ return new ColumnTypeChanger(stepList, stepName, tableName, columnName, Datatype.BIGDECIMAL, newPrecision, newScale, includeAudTable, null, false, null, true, newSecondColumnName);\r
+ }\r
+\r
+ protected ColumnTypeChanger(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String columnName, Datatype newColumnType, Integer size, Integer scale,\r
+ boolean includeAudTable, Object defaultValue, boolean notNull, String referencedTable, boolean isBigDecimal, String secondColumnName) {\r
\r
- protected ColumnTypeChanger(List<ISchemaUpdaterStep> stepList, String stepName, String tableName, String columnName, Datatype newColumnType, Integer size, boolean includeAudTable, Object defaultValue, boolean notNull, String referencedTable) {\r
- super(stepList, stepName, tableName, includeAudTable);\r
+ super(stepList, stepName, tableName, includeAudTable);\r
this.columnName = columnName;\r
this.newColumnType = newColumnType;\r
this.newSize = size;\r
this.defaultValue = defaultValue;\r
this.isNotNull = notNull;\r
this.referencedTable = referencedTable;\r
+ this.newScale = scale;\r
+ this.isBigDecimal = isBigDecimal;\r
+ this.secondColumnName = secondColumnName;\r
}\r
\r
@Override\r
public String getUpdateQueryString(String tableName, ICdmDataSource datasource, IProgressMonitor monitor) throws DatabaseTypeNotSupportedException {\r
String updateQuery;\r
DatabaseTypeEnum type = datasource.getDatabaseType();\r
- String databaseColumnType = getDatabaseColumnType(datasource, this.newColumnType, newSize);\r
+ String databaseColumnType = getDatabaseColumnType(datasource, this.newColumnType, newSize, newScale);\r
\r
if (type.equals(DatabaseTypeEnum.SqlServer2005)){\r
//MySQL allows both syntaxes\r
//\r
boolean includeAuditing = false;\r
String colNameChanged = this.columnName + _OLDXXX;\r
- String databaseColumnType = getDatabaseColumnType(datasource, this.newColumnType, newSize);\r
+ String databaseColumnType = getDatabaseColumnType(datasource, this.newColumnType, newSize, newScale);\r
\r
//change old column name\r
//note data type is not relevant for ColumnNameChanger with Postgres\r
//create new column\r
// step = ColumnAdder.NewStringInstance(this.stepName + " - Add new column", tableName, this.columnName, includeAuditing);\r
Object defaultValue = null;\r
- step = new ColumnAdder(null, this.stepName + " - Add new column", tableName, this.columnName, newColumnType, newSize, includeAuditing, defaultValue, false, null);\r
+ step = new ColumnAdder(null, this.stepName + " - Add new column", tableName, this.columnName, newColumnType, newSize, null, includeAuditing, defaultValue, false, null);\r
step.invoke(datasource, monitor, caseType, result);\r
\r
//move data\r
step.invoke(datasource, monitor, caseType, result);\r
}\r
\r
- private String getDatabaseColumnType(ICdmDataSource datasource, Datatype columnType, Integer size) {\r
- return columnType.format(datasource, size);\r
+ private String getDatabaseColumnType(ICdmDataSource datasource, Datatype columnType, Integer size, Integer scale) {\r
+ return columnType.format(datasource, size, scale);\r
}\r
\r
public String getReferencedTable() {\r
VARCHAR("varchar"),
DATETIME("datetime"),
DOUBLE("double"),
+ FLOAT("float"),
TINYINTEGER("tinyint"),
- BIT("bit")
+ BIT("bit"),
+ BIGDECIMAL("decimal"),
;
private String defaultStr;
}
public String format(ICdmDataSource datasource, Integer size) {
+ return format(datasource, size, null);
+ }
+
+ public String format(ICdmDataSource datasource, Integer size, Integer scale) {
String result = defaultStr;
DatabaseTypeEnum dbType = datasource.getDatabaseType();
//nvarchar
if (dbType.equals(DatabaseTypeEnum.PostgreSQL)){ //TODO use PostgeSQL82 Dialect infos
result = result.replace("nvarchar", "varchar");
- result = result.replace("double", "float8");
- result = result.replace("bit", DatabaseTypeEnum.PostgreSQL.getHibernateDialect().getTypeName(Types.BIT));
- result = result.replace("datetime", DatabaseTypeEnum.PostgreSQL.getHibernateDialect().getTypeName(Types.TIMESTAMP));
+ result = result.replace("float", dbType.getHibernateDialect().getTypeName(Types.FLOAT));
+ result = result.replace("double", dbType.getHibernateDialect().getTypeName(Types.DOUBLE));
+ result = result.replace("bit", dbType.getHibernateDialect().getTypeName(Types.BIT));
+ result = result.replace("datetime", dbType.getHibernateDialect().getTypeName(Types.TIMESTAMP));
result = result.replace("tinyint", DatabaseTypeEnum.PostgreSQL.getHibernateDialect().getTypeName(Types.TINYINT));
}
//CLOB
}
}else if (this == VARCHAR){
result = result + "(" + size + ")";
+ }else if (this == BIGDECIMAL){
+ result = result + "(" + size + "," + scale + ")";
}
return result;
}
--- /dev/null
+/**
+* Copyright (C) 2020 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.database.update;
+
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
+import eu.etaxonomy.cdm.database.ICdmDataSource;
+import eu.etaxonomy.cdm.hibernate.BigDecimalUserType;
+
+/**
+ * Changes a float column into a BigDecimal (2 columns) for usage in {@link BigDecimalUserType}.
+ * First renames the old column and creates the 2 new columns via {@link #getInnerSteps() inner steps}
+ * and then fills the new columns by using the mapping algorithm defined in
+ * {@link #invokeOnTable(String, ICdmDataSource, IProgressMonitor, CaseType, SchemaUpdateResult)}.
+ *
+ * Does not yet delete the old column. This should be done in a follow up model update.
+ *
+ * @author a.mueller
+ * @since 27.04.2020
+ */
+public class Float2BigDecimalTypeChanger extends AuditedSchemaUpdaterStepBase {
+
+ private static final String OLD_POSTFIX = "_old";
+
+ private final String valueColumn;
+ private final String scaleColumn;
+ private final Integer newScale;
+ private final Integer newPrecision;
+ private final boolean isNotNull = false;
+ private boolean isRounder = false;
+
+ public static Float2BigDecimalTypeChanger NewInstance (List<? extends ISchemaUpdaterStep> stepList,
+ String stepName, String tableName, String valueColumn, String scaleColumn, Integer newPrecision, Integer newScale,
+ boolean includedAudTable){
+ return new Float2BigDecimalTypeChanger(stepList, stepName, tableName, valueColumn,
+ scaleColumn, newPrecision, newScale, includedAudTable);
+ }
+
+ protected Float2BigDecimalTypeChanger(List<? extends ISchemaUpdaterStep> stepList,
+ String stepName, String tableName, String valueColumn, String scaleColumn,
+ Integer newPrecision, Integer newScale, boolean includedAudTable) {
+ super(stepList, stepName, tableName, includedAudTable);
+ this.valueColumn = valueColumn;
+ this.scaleColumn = scaleColumn;
+ this.newPrecision = newPrecision;
+ this.newScale = newScale;
+ }
+
+ @Override
+ protected void invokeOnTable(String tableName, ICdmDataSource datasource, IProgressMonitor monitor,
+ CaseType caseType, SchemaUpdateResult result) {
+ if(!isRounder){
+ return;
+ }
+ String sql = "SELECT id, %s as value_float FROM %s as t ";
+ sql = String.format(sql, valueColumn+OLD_POSTFIX, tableName);
+ try {
+ ResultSet rs = datasource.executeQuery(sql);
+ while(rs.next()){
+ Float floatValue = rs.getFloat("value_float");
+ BigDecimal bd = new BigDecimal(floatValue.toString());
+ int id = rs.getInt("id");
+ sql = "UPDATE %s SET %s = %s, %s = %s WHERE id = %s ";
+ sql = String.format(sql, tableName, valueColumn, bd.toString(), scaleColumn, bd.scale(), String.valueOf(id));
+ datasource.executeUpdate(sql);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @Override
+ public List<ISchemaUpdaterStep> getInnerSteps() {
+ if(!isRounder){
+ List<ISchemaUpdaterStep> result = new ArrayList<>();
+ ColumnNameChanger.NewFloatInstance(result, stepName + " - rename old column", tableName, valueColumn, valueColumn + OLD_POSTFIX, includeAudTable);
+ ColumnAdder.NewDecimalInstance(result, stepName + " - add value column", tableName, valueColumn, newPrecision, newScale, includeAudTable, 0, isNotNull);
+ ColumnAdder.NewIntegerInstance(result, stepName + " - add scale column", tableName, scaleColumn, includeAudTable, newScale, isNotNull);
+ Float2BigDecimalTypeChanger rounder = Float2BigDecimalTypeChanger.NewInstance(result, stepName + " - round", tableName, valueColumn, scaleColumn, newPrecision, newScale, this.includeAudTable);
+ rounder.isRounder = true;
+ return result;
+ }else{
+ return super.getInnerSteps();
+ }
+ }
+
+}
import org.apache.log4j.Logger;
+import eu.etaxonomy.cdm.database.update.Float2BigDecimalTypeChanger;
import eu.etaxonomy.cdm.database.update.ISchemaUpdater;
import eu.etaxonomy.cdm.database.update.ISchemaUpdaterStep;
import eu.etaxonomy.cdm.database.update.SchemaUpdaterBase;
TermRepresentationUpdater.NewInstanceWithTitleCache(stepList, stepName,
uuidTerm, label, label, null, uuidLanguage);
+ //#8978
+ stepName = "make statistical measurment value BigDecimal";
+ tableName = "StatisticalMeasurementValue";
+ columnName = "value";
+ String scaleColumnName = "value_scale";
+ int newPrecision = 18;
+ int newScale = 9;
+// ColumnTypeChanger.NewFloat2BigDecimalInstance(stepList, stepName, tableName, columnName, scaleColumnName, newPrecision, newScale, INCLUDE_AUDIT);
+ Float2BigDecimalTypeChanger.NewInstance(stepList, stepName, tableName, columnName, scaleColumnName, newPrecision, newScale, INCLUDE_AUDIT);
+
return stepList;
}
--- /dev/null
+/**
+* Copyright (C) 2020 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.hibernate;
+
+import java.io.FileNotFoundException;
+import java.math.BigDecimal;
+import java.sql.Types;
+
+import org.hibernate.usertype.UserType;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import eu.etaxonomy.cdm.test.integration.CdmTransactionalIntegrationTest;
+
+/**
+ * Test for {@link BigDecimalUserType}
+ *
+ * The test class has originally been copied and adapted from
+ * https://bitbucket.org/ratkins/bigdecimalusertype/src/default/BigDecimalUserTypeTest.java
+ *
+ * @author a.mueller
+ * @since 27.04.2020
+ */
+public class BigDecimalUserTypeTest extends CdmTransactionalIntegrationTest {
+
+// @Mock ResultSet rs;
+// @Mock PreparedStatement st;
+
+ private UserType userType;
+
+ @Before
+ public void setUp() throws Exception {
+ userType = new BigDecimalUserType();
+ }
+
+ @Test
+ public void testNotMutable() throws Exception {
+ Assert.assertFalse(userType.isMutable());
+ }
+
+ @Test
+ public void testDeepCopyReturnsSelf() throws Exception {
+ BigDecimal foo = new BigDecimal("1.0");
+ Assert.assertSame(userType.deepCopy(foo), foo);
+ }
+
+ @Test
+ public void testReturnedClassIsBigDecimal() throws Exception {
+ Assert.assertEquals(userType.returnedClass(), BigDecimal.class);
+ Assert.assertTrue(userType.returnedClass() == BigDecimal.class);
+ }
+
+ @Test
+ public void testEqualsDelegatesToBigDecimalEquals() throws Exception {
+ Assert.assertTrue(userType.equals(new BigDecimal("1.0"), new BigDecimal("1.0")));
+ Assert.assertFalse(userType.equals(new BigDecimal("1.0"), new BigDecimal("2.0")));
+ Assert.assertFalse(userType.equals(new BigDecimal("1.0"), new BigDecimal("1.00")));
+ }
+
+ @Test
+ public void testHashCodeDelegatesToBigDecimalHashCode() throws Exception {
+ Assert.assertEquals(userType.hashCode(new BigDecimal("1.0")), new BigDecimal("1.0").hashCode());
+ Assert.assertNotEquals(userType.hashCode(new BigDecimal("1.00")), new BigDecimal("1.0").hashCode());
+ Assert.assertNotEquals(userType.hashCode(new BigDecimal("1.0")), new BigDecimal("2.0").hashCode());
+ }
+
+ @Test
+ public void testAssembleReturnsSelf() throws Exception {
+ BigDecimal foo = new BigDecimal("1.0");
+ Assert.assertSame(userType.assemble(foo, null), foo);
+ }
+
+ @Test
+ public void testDisassembleReturnsSelf() throws Exception {
+ BigDecimal foo = new BigDecimal("1.0");
+ Assert.assertSame(userType.disassemble(foo), foo);
+ Assert.assertEquals(userType.disassemble(null), (BigDecimal) null);
+ }
+
+ @Test
+ public void testReplaceReturnsSelf() throws Exception {
+ BigDecimal foo = new BigDecimal("1.0");
+ Assert.assertSame(userType.replace(foo, null, null), foo);
+ Assert.assertEquals(userType.disassemble(null), (BigDecimal) null);
+ }
+
+ @Test
+ public void testSqlTypesAreNumberAndInteger() throws Exception {
+ Assert.assertEquals(userType.sqlTypes().length, 2);
+ Assert.assertEquals(userType.sqlTypes()[0], Types.NUMERIC); //Types.DECIMAL does not work (tested for MySQL)
+ Assert.assertEquals(userType.sqlTypes()[1], Types.INTEGER);
+ }
+
+ //TODO update tests from original file
+// @Test
+// public void testNullSafeGet() throws Exception {
+// when(rs.getBigDecimal("a")).thenReturn(new BigDecimal("1.000000"));
+// when(rs.getInt("b")).thenReturn(1);
+//
+// assertThat((BigDecimal) userType.nullSafeGet(rs, new String[] {"a", "b"}, null), equalTo(new BigDecimal("1.0")));
+// }
+//
+// @Test
+// public void testNullSafeGetWithNull() throws Exception {
+// when(rs.getBigDecimal("a")).thenReturn(null);
+// when(rs.getInt("b")).thenReturn(0);
+//
+// assertThat((BigDecimal) userType.nullSafeGet(rs, new String[] {"a", "b"}, null), equalTo((BigDecimal) null));
+// }
+//
+// @Test
+// public void testNullSafeSet() throws Exception {
+// userType.nullSafeSet(st, new BigDecimal("1.000"), 17);
+//
+// verify(st).setBigDecimal(17, new BigDecimal("1.000"));
+// verify(st).setInt(18, 3);
+// }
+//
+// @Test
+// public void testNullSafeSetWithNull() throws Exception {
+// userType.nullSafeSet(st, null, 17);
+//
+// verify(st).setNull(17, Types.NUMERIC);
+// verify(st).setNull(18, Types.INTEGER);
+// }
+
+
+ @Override
+ public void createTestDataSet() throws FileNotFoundException {}
+}
package eu.etaxonomy.cdm.api.service;
+import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import eu.etaxonomy.cdm.model.description.TextData;
public abstract class AbstractQuantitativeDescriptionBuilder extends DescriptionBuilder<QuantitativeData>{
-
- public TextData build(QuantitativeData data, List<Language> languages) {
- Map<StatisticalMeasure,Float> measures = new HashMap<StatisticalMeasure,Float>();
+
+ @Override
+ public TextData build(QuantitativeData data, List<Language> languages) {
+ Map<StatisticalMeasure,BigDecimal> measures = new HashMap<>();
for (StatisticalMeasurementValue smv : data.getStatisticalValues()){
measures.put(smv.getType(),smv.getValue());
}
return doBuild(measures,data.getUnit(), languages);
}
-
- protected abstract TextData doBuild(Map<StatisticalMeasure,Float> measures, MeasurementUnit unit, List<Language> languages);
+
+ protected abstract TextData doBuild(Map<StatisticalMeasure,BigDecimal> measures,
+ MeasurementUnit unit, List<Language> languages);
}
package eu.etaxonomy.cdm.api.service;
+import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
private String space = " ";
@Override
- protected TextData doBuild(Map<StatisticalMeasure,Float> measures, MeasurementUnit mUnit, List<Language> languages){
+ protected TextData doBuild(Map<StatisticalMeasure,BigDecimal> measures, MeasurementUnit mUnit, List<Language> languages){
StringBuilder QuantitativeDescription = new StringBuilder(); // this StringBuilder is used to concatenate the different words of the description before saving it in the TextData
TextData textData = TextData.NewInstance(); // TextData that will contain the description and the language corresponding
// booleans indicating whether a kind of value is present or not and the float that will eventually hold the value
// the booleans and floats are updated according to the presence or absence of values
Boolean max, min, upperb, lowerb, average, sd;
-
- String averagevalue = getValue(measures,StatisticalMeasure.AVERAGE());
- if (averagevalue!=null) average=true; else average=false;
- String sdvalue = getValue(measures,StatisticalMeasure.STANDARD_DEVIATION());
- if (sdvalue!=null) sd=true; else sd=false;
- String minvalue = getValue(measures,StatisticalMeasure.MIN());
- if (minvalue!=null) min=true; else min=false;
- String maxvalue = getValue(measures,StatisticalMeasure.MAX());
- if (maxvalue!=null) max=true; else max=false;
- String lowerbvalue = getValue(measures,StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
- if (lowerbvalue!=null) lowerb=true; else lowerb=false;
- String upperbvalue = getValue(measures,StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
- if (upperbvalue!=null) upperb=true; else upperb=false;
-
-
- // depending on the different associations of values, a sentence is built
+
+ String averagevalue = getValue(measures, StatisticalMeasure.AVERAGE());
+ if (averagevalue!=null) {
+ average=true;
+ } else {
+ average=false;
+ }
+ String sdvalue = getValue(measures, StatisticalMeasure.STANDARD_DEVIATION());
+ if (sdvalue!=null) {
+ sd=true;
+ } else {
+ sd=false;
+ }
+ String minvalue = getValue(measures, StatisticalMeasure.MIN());
+ if (minvalue!=null) {
+ min=true;
+ } else {
+ min=false;
+ }
+ String maxvalue = getValue(measures, StatisticalMeasure.MAX());
+ if (maxvalue!=null) {
+ max=true;
+ } else {
+ max=false;
+ }
+ String lowerbvalue = getValue(measures, StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
+ if (lowerbvalue!=null) {
+ lowerb=true;
+ } else {
+ lowerb=false;
+ }
+ String upperbvalue = getValue(measures, StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
+ if (upperbvalue!=null) {
+ upperb=true;
+ } else {
+ upperb=false;
+ }
+
+
+ // depending on the different associations of values, a sentence is built
if (max && min) {
QuantitativeDescription.append(space + from + space + minvalue + space + to + space + maxvalue + space + unit);
}
* @param key the desired measure
* @return
*/
- private String getValue(Map<StatisticalMeasure,Float> measures, Object key) {
- Float floatValue;
+ private String getValue(Map<StatisticalMeasure,BigDecimal> measures, Object key) {
+ BigDecimal floatValue;
Integer intValue;
if(measures.containsKey(key)) {
floatValue = measures.get(key);
package eu.etaxonomy.cdm.api.service;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
private DescriptionElementBase element;
private Set<UUID> stateUuids = new HashSet<>();
- private Set<Float> avgs = new HashSet<>();
- private Set<Float> exacts = new HashSet<>();
- private Set<Float> maxs = new HashSet<>();
- private Set<Float> mins = new HashSet<>();
- private Set<Float> sampleSizes = new HashSet<>();
- private Set<Float> standardDevs = new HashSet<>();
- private Set<Float> lowerBounds = new HashSet<>();
- private Set<Float> upperBounds = new HashSet<>();
- private Set<Float> variances = new HashSet<>();
+ private Set<BigDecimal> avgs = new HashSet<>();
+ private Set<BigDecimal> exacts = new HashSet<>();
+ private Set<BigDecimal> maxs = new HashSet<>();
+ private Set<BigDecimal> mins = new HashSet<>();
+ private Set<BigDecimal> sampleSizes = new HashSet<>();
+ private Set<BigDecimal> standardDevs = new HashSet<>();
+ private Set<BigDecimal> lowerBounds = new HashSet<>();
+ private Set<BigDecimal> upperBounds = new HashSet<>();
+ private Set<BigDecimal> variances = new HashSet<>();
public DescriptionElementCompareWrapper(DescriptionElementBase element) {
this.element = element;
package eu.etaxonomy.cdm.api.service;
+import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
private String spanEnd = "</span>";
@Override
- protected TextData doBuild(Map<StatisticalMeasure,Float> measures, MeasurementUnit mUnit, List<Language> languages){
+ protected TextData doBuild(Map<StatisticalMeasure,BigDecimal> measures, MeasurementUnit mUnit,
+ List<Language> languages){
StringBuilder QuantitativeDescription = new StringBuilder(); // this StringBuilder is used to concatenate the different words of the description before saving it in the TextData
TextData textData = TextData.NewInstance(); // TextData that will contain the description and the language corresponding
*/
package eu.etaxonomy.cdm.api.service.description;
+import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
+import eu.etaxonomy.cdm.common.BigDecimalUtil;
import eu.etaxonomy.cdm.model.common.CdmBase;
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
import eu.etaxonomy.cdm.model.description.CategoricalData;
private QuantitativeData aggregateSingleQuantitativeData(QuantitativeData sourceQd){
QuantitativeData aggQD = QuantitativeData.NewInstance(sourceQd.getFeature());
- Set<Float> exactValues = sourceQd.getExactValues();
+ Set<BigDecimal> exactValues = sourceQd.getExactValues();
if(!exactValues.isEmpty()){
+ Comparator<BigDecimal> comp = Comparator.naturalOrder();
// qd is not already aggregated
- float exactValueSampleSize = exactValues.size();
- float exactValueMin = new Float(exactValues.stream().mapToDouble(value->(double)value).min().getAsDouble());
- float exactValueMax = new Float(exactValues.stream().mapToDouble(value->(double)value).max().getAsDouble());
- float exactValueAvg = new Float(exactValues.stream().mapToDouble(value->(double)value).average().getAsDouble());
+ int exactValueSampleSize = exactValues.size();
+ BigDecimal exactValueMin = exactValues.stream().min(comp).get();
+ BigDecimal exactValueMax = exactValues.stream().max(comp).get();
+ BigDecimal exactValueAvg = BigDecimalUtil.average(exactValues);
//TODO also check for typical boundary data
if(sourceQd.getMin() == null && sourceQd.getMax() == null){
- aggQD.setSampleSize(exactValueSampleSize, null);
+ aggQD.setSampleSize(new BigDecimal(exactValueSampleSize), null);
aggQD.setAverage(exactValueAvg, null);
}
- aggQD.setMinimum(sourceQd.getMin() == null ? exactValueMin: Math.min(sourceQd.getMin(), exactValueMin), null);
- aggQD.setMaximum(sourceQd.getMax() == null ? exactValueMax: Math.min(sourceQd.getMax(), exactValueMax), null);
+ aggQD.setMinimum(sourceQd.getMin() == null ? exactValueMin: sourceQd.getMin().min(exactValueMin), null);
+ aggQD.setMaximum(sourceQd.getMax() == null ? exactValueMax: sourceQd.getMax().max(exactValueMax), null);
}
else{
// qd has only min, max, ... but no exact values
private QuantitativeData handleMissingValues(QuantitativeData qd) {
qd = handleMissingMinOrMax(qd);
if (qd != null && qd.getAverage() == null){
- Float n = qd.getSampleSize();
+ BigDecimal n = qd.getSampleSize();
if(n != null && !n.equals(0f)){
- qd.setAverage((qd.getMax()+qd.getMin())/n, null);
+ qd.setAverage((qd.getMax().add(qd.getMin())).divide(n), null);
}
}
return qd;
MissingMaximumMode missingMaxMode) {
if(aggQD.getMin() == null && aggQD.getMax() != null){
if (missingMinMode == MissingMinimumMode.MinToZero) {
- aggQD.setMinimum(0f, null);
+ aggQD.setMinimum(BigDecimal.valueOf(0f), null);
}else if (missingMinMode == MissingMinimumMode.MinToMax){
aggQD.setMinimum(aggQD.getMax(), null);
}else if (missingMinMode == MissingMinimumMode.SkipRecord){
newQd = aggregateSingleQuantitativeData(newQd); //alternatively we could check, if newQd is already basically aggregated, but for this we need a cleear definition what the minimum requirements are and how ExactValues and MinMax if existing in parallel should be handled.
- Float min = null;
- Float max = null;
- Float average = null;
- Float sampleSize = null;
+ BigDecimal min = null;
+ BigDecimal max = null;
+ BigDecimal average = null;
+ BigDecimal sampleSize = null;
newQd = handleMissingValues(newQd);
if (newQd == null){
return aggQd;
}
- min = Math.min(aggQd.getMin(), newQd.getMin());
- max = Math.max(aggQd.getMax(), newQd.getMax());
- if (newQd.getSampleSize()!= null && aggQd.getSampleSize() != null){
- sampleSize = newQd.getSampleSize()+aggQd.getSampleSize();
+ min = aggQd.getMin().min(newQd.getMin());
+ max = aggQd.getMax().max(newQd.getMax());
+ if (newQd.getSampleSize() != null && aggQd.getSampleSize() != null){
+ sampleSize = newQd.getSampleSize().add(aggQd.getSampleSize());
}
if (sampleSize != null && !sampleSize.equals(0f) && aggQd.getAverage() != null && newQd.getAverage() != null){
- float totalSum = aggQd.getAverage()*aggQd.getSampleSize() + newQd.getAverage() * newQd.getSampleSize();
- average = new Float(totalSum/sampleSize);
+ BigDecimal totalSum = aggQd.getAverage().multiply(aggQd.getSampleSize()).add(newQd.getAverage().multiply(newQd.getSampleSize()));
+ average = totalSum.divide(sampleSize);
}
aggQd.setMinimum(min, null);
aggQd.setMaximum(max, null);
return aggQd;
}
- private static List<Float> getExactValues(QuantitativeData qd) {
- List<Float> exactValues = qd.getStatisticalValues().stream()
+ private static List<BigDecimal> getExactValues(QuantitativeData qd) {
+ List<BigDecimal> exactValues = qd.getStatisticalValues().stream()
.filter(value->value.getType().equals(StatisticalMeasure.EXACT_VALUE()))
.map(exact->exact.getValue())
.collect(Collectors.toList());
package eu.etaxonomy.cdm.api.service.dto;
import java.io.Serializable;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
private String generateQuantitativeDataString(QuantitativeData quantitativeData) {
String displayData;
displayData = "";
- Float min = quantitativeData.getMin();
- Float max = quantitativeData.getMax();
+ BigDecimal min = quantitativeData.getMin();
+ BigDecimal max = quantitativeData.getMax();
if(min!=null||max!=null){
displayData += "["+(min!=null?min.toString():"?")+"-"+(max!=null?max.toString():"?")+"] ";
}
- displayData += quantitativeData.getStatisticalValues().stream().
- filter(value->value.getType().equals(StatisticalMeasure.EXACT_VALUE()))
- .map(exact->Float.toString(exact.getValue()))
- .collect(Collectors.joining(", "));
+ displayData += quantitativeData.getStatisticalValues().stream()
+ .filter(value->value.getType().equals(StatisticalMeasure.EXACT_VALUE()))
+ .map(exact->exact.getValue().toString())
+ .collect(Collectors.joining(", "));
if (quantitativeData.getUnit() != null){
displayData += " "+ quantitativeData.getUnit().getIdInVocabulary();
}
texts.forEach(text->{
String string = text;
try {
- float exactValue = Float.parseFloat(string);
+ BigDecimal exactValue = new BigDecimal(string);
quantitativeData.addStatisticalValue(StatisticalMeasurementValue.NewInstance(measure, exactValue));
} catch (NumberFormatException e) {
}
import static org.junit.Assert.assertTrue;
import java.io.FileNotFoundException;
+import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
MeasurementUnit munit = MeasurementUnit.NewInstance(null, "mm", null);
StatisticalMeasurementValue smv = StatisticalMeasurementValue.NewInstance();
smv.setType(StatisticalMeasure.AVERAGE());
- smv.setValue(12);
+ smv.setValue(new BigDecimal(12));
qd.addStatisticalValue(smv);
qd.setUnit(munit);
qd.setFeature(qFeature);
package eu.etaxonomy.cdm.api.service.description;
import java.io.FileNotFoundException;
+import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
import java.util.UUID;
datasetService.save(dataSet);
SpecimenDescription specDescAlpina1 = createSpecimenDescription(dataSet, T_LAPSANA_COMMUNIS_ALPINA_UUID, "alpina specimen1");
- addQuantitativeData(specDescAlpina1, uuidFeatureLeafLength, StatisticalMeasure.MIN(), 5.0f);
+ addQuantitativeData(specDescAlpina1, uuidFeatureLeafLength, StatisticalMeasure.MIN(), new BigDecimal("5.0"));
SpecimenDescription specDescAlpina2 = createSpecimenDescription(dataSet, T_LAPSANA_COMMUNIS_ALPINA_UUID, "alpina specimen2");
- addQuantitativeData(specDescAlpina2, uuidFeatureLeafLength, StatisticalMeasure.MAX(), 7.0f);
+ addQuantitativeData(specDescAlpina2, uuidFeatureLeafLength, StatisticalMeasure.MAX(), new BigDecimal("7.0"));
TaxonNode tnLapsana = taxonNodeService.find(TN_LAPSANA_UUID);
Assert.assertNotNull(tnLapsana);
SpecimenDescription specDescAlpina1 = createSpecimenDescription(dataSet, T_LAPSANA_COMMUNIS_ALPINA_UUID, "alpina specimen1");
addCategoricalData(specDescAlpina1, uuidFeatureLeafPA, State.uuidPresent);
- addQuantitativeData(specDescAlpina1, uuidFeatureLeafLength, StatisticalMeasure.EXACT_VALUE(), 5.0f);
+ addQuantitativeData(specDescAlpina1, uuidFeatureLeafLength, StatisticalMeasure.EXACT_VALUE(), new BigDecimal("5.0"));
addCategoricalData(specDescAlpina1, uuidFeatureLeafColor, uuidLeafColorBlue);
SpecimenDescription specDescAlpina2 = createSpecimenDescription(dataSet, T_LAPSANA_COMMUNIS_ALPINA_UUID, "alpina specimen2");
addCategoricalData(specDescAlpina2, uuidFeatureLeafPA, State.uuidPresent);
- addQuantitativeData(specDescAlpina2, uuidFeatureLeafLength, StatisticalMeasure.EXACT_VALUE(), 7.0f);
+ addQuantitativeData(specDescAlpina2, uuidFeatureLeafLength, StatisticalMeasure.EXACT_VALUE(), new BigDecimal("7.0"));
addCategoricalData(specDescAlpina2, uuidFeatureLeafColor, uuidLeafColorBlue);
SpecimenDescription specDescAdenophora = createSpecimenDescription(dataSet, T_LAPSANA_COMMUNIS_ADENOPHORA_UUID, "adenophora specimen");
addCategoricalData(specDescAdenophora, uuidFeatureLeafPA, State.uuidPresent);
- addQuantitativeData(specDescAdenophora, uuidFeatureLeafLength, StatisticalMeasure.EXACT_VALUE(), 12.0f);
+ addQuantitativeData(specDescAdenophora, uuidFeatureLeafLength, StatisticalMeasure.EXACT_VALUE(), new BigDecimal("12.0"));
addCategoricalData(specDescAdenophora, uuidFeatureLeafColor, uuidLeafColorYellow);
TaxonNode tnLapsana = taxonNodeService.find(TN_LAPSANA_UUID);
Assert.assertEquals(stateUuid, stateData.getState().getUuid());
}
- private void addQuantitativeData(SpecimenDescription specDesc, UUID uuidFeature, StatisticalMeasure type, float value) {
+ private void addQuantitativeData(SpecimenDescription specDesc, UUID uuidFeature, StatisticalMeasure type, BigDecimal value) {
Feature feature = (Feature)termService.find(uuidFeature);
QuantitativeData qd = QuantitativeData.NewInstance(feature);
StatisticalMeasurementValue smv = StatisticalMeasurementValue.NewInstance(type, value);