/** * Copyright (C) 2011-2012 Typesafe Inc. <http://typesafe.com> */ package org.deephacks.confit.internal.core.property.typesafe.impl; import java.io.ObjectStreamException; import java.io.Serializable; import org.deephacks.confit.internal.core.property.typesafe.ConfigException; import org.deephacks.confit.internal.core.property.typesafe.ConfigOrigin; abstract class ConfigNumber extends AbstractConfigValue implements Serializable { private static final long serialVersionUID = 2L; // This is so when we concatenate a number into a string (say it appears in // a sentence) we always have it exactly as the person typed it into the // typesafe file. It's purely cosmetic; equals/hashCode don't consider this // for example. final protected String originalText; protected ConfigNumber(ConfigOrigin origin, String originalText) { super(origin); this.originalText = originalText; } @Override public abstract Number unwrapped(); @Override String transformToString() { return originalText; } int intValueRangeChecked(String path) { long l = longValue(); if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { throw new ConfigException.WrongType(origin(), path, "32-bit integer", "out-of-range value " + l); } return (int) l; } protected abstract long longValue(); protected abstract double doubleValue(); private boolean isWhole() { long asLong = longValue(); return asLong == doubleValue(); } @Override protected boolean canEqual(Object other) { return other instanceof ConfigNumber; } @Override public boolean equals(Object other) { // note that "origin" is deliberately NOT part of equality if (other instanceof ConfigNumber && canEqual(other)) { ConfigNumber n = (ConfigNumber) other; if (isWhole()) { return n.isWhole() && this.longValue() == n.longValue(); } else { return (!n.isWhole()) && this.doubleValue() == n.doubleValue(); } } else { return false; } } @Override public int hashCode() { // note that "origin" is deliberately NOT part of equality // this matches what standard Long.hashCode and Double.hashCode // do, though I don't think it really matters. long asLong; if (isWhole()) { asLong = longValue(); } else { asLong = Double.doubleToLongBits(doubleValue()); } return (int) (asLong ^ (asLong >>> 32)); } static ConfigNumber newNumber(ConfigOrigin origin, long number, String originalText) { if (number <= Integer.MAX_VALUE && number >= Integer.MIN_VALUE) return new ConfigInt(origin, (int) number, originalText); else return new ConfigLong(origin, number, originalText); } static ConfigNumber newNumber(ConfigOrigin origin, double number, String originalText) { long asLong = (long) number; if (asLong == number) { return newNumber(origin, asLong, originalText); } else { return new ConfigDouble(origin, number, originalText); } } // serialization list goes through SerializedConfigValue private Object writeReplace() throws ObjectStreamException { return new SerializedConfigValue(this); } }