DATACMNS-437 - Polishing of newly introduced geo value objects.

Polished JavaDoc. Simplified equals(…) and hashCode() methods where possible. Added additional null checks where appropriate. Removed obsolete generics in Polygon and switched to an immutable collection for the Points making up the Polygon.

Related pull request: #68.
This commit is contained in:
Oliver Gierke
2014-03-07 08:58:48 +01:00
parent e4dfda29a3
commit 94db475afe
11 changed files with 166 additions and 59 deletions

View File

@@ -60,28 +60,52 @@ public class Box implements Shape {
this.second = new Point(second[0], second[1]);
}
/**
* Returns the first {@link Point} making up the {@link Box}.
*
* @return
*/
public Point getFirst() {
return first;
}
/**
* Returns the second {@link Point} making up the {@link Box}.
*
* @return
*/
public Point getSecond() {
return second;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("Box [%s, %s]", first, second);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 31;
result += 17 * first.hashCode();
result += 17 * second.hashCode();
return result;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
@@ -89,11 +113,12 @@ public class Box implements Shape {
return true;
}
if (obj == null || !(obj instanceof Box)) {
if (!(obj instanceof Box)) {
return false;
}
Box that = (Box) obj;
return this.first.equals(that.first) && this.second.equals(that.second);
}
}

View File

@@ -54,7 +54,6 @@ public class Circle implements Shape {
* @param center must not be {@literal null}.
* @param radius's value must be greater or equal to zero.
*/
@PersistenceConstructor
public Circle(Point center, double radius) {
this(center, new Distance(radius));
}
@@ -95,10 +94,11 @@ public class Circle implements Shape {
*/
@Override
public String toString() {
return String.format("Circle [center=%s, radius=%f]", center, radius);
return String.format("Circle: [center=%s, radius=%f]", center, radius);
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -108,7 +108,7 @@ public class Circle implements Shape {
return true;
}
if (obj == null || !(obj instanceof Circle)) {
if (!(obj instanceof Circle)) {
return false;
}
@@ -123,9 +123,12 @@ public class Circle implements Shape {
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * center.hashCode();
result += 31 * radius.hashCode();
return result;
}
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.geo;
import org.springframework.util.ObjectUtils;
import org.springframework.util.Assert;
/**
* Value object to represent distances in a given metric.
@@ -42,7 +42,7 @@ public class Distance {
* Creates a new {@link Distance} with the given {@link Metric}.
*
* @param value
* @param metric
* @param metric can be {@literal null}.
*/
public Distance(double value, Metric metric) {
this.value = value;
@@ -50,6 +50,8 @@ public class Distance {
}
/**
* Returns the distance value in the current {@link Metric}.
*
* @return the value
*/
public double getValue() {
@@ -66,6 +68,8 @@ public class Distance {
}
/**
* Retruns the {@link Metric} of the {@link Distance}.
*
* @return the metric
*/
public Metric getMetric() {
@@ -76,24 +80,33 @@ public class Distance {
* Adds the given distance to the current one. The resulting {@link Distance} will be in the same metric as the
* current one.
*
* @param other
* @param other must not be {@literal null}.
* @return
*/
public Distance add(Distance other) {
Assert.notNull(other, "Distance to add must not be null!");
double newNormalizedValue = getNormalizedValue() + other.getNormalizedValue();
return new Distance(newNormalizedValue * metric.getMultiplier(), metric);
}
/**
* Adds the given {@link Distance} to the current one and forces the result to be in a given {@link Metric}.
*
* @param other
* @param metric
* @param other must not be {@literal null}.
* @param metric must not be {@literal null}.
* @return
*/
public Distance add(Distance other, Metric metric) {
Assert.notNull(other, "Distance to must not be null!");
Assert.notNull(metric, "Result metric must not be null!");
double newLeft = getNormalizedValue() * metric.getMultiplier();
double newRight = other.getNormalizedValue() * metric.getMultiplier();
return new Distance(newLeft + newRight, metric);
}
@@ -108,13 +121,13 @@ public class Distance {
return true;
}
if (obj == null || !getClass().isInstance(obj)) {
if (!(obj instanceof Distance)) {
return false;
}
Distance that = (Distance) obj;
return this.value == that.value && ObjectUtils.nullSafeEquals(this.metric, that.metric);
return this.value == that.value && this.metric.equals(that.metric);
}
/*
@@ -123,9 +136,12 @@ public class Distance {
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * Double.doubleToLongBits(value);
result += 31 * ObjectUtils.nullSafeHashCode(metric);
result += 31 * metric.hashCode();
return result;
}

View File

@@ -38,7 +38,9 @@ public class GeoPage<T> extends PageImpl<GeoResult<T>> {
* @param content must not be {@literal null}.
*/
public GeoPage(GeoResults<T> results) {
super(results.getContent());
this.averageDistance = results.getAverageDistance();
}
@@ -50,7 +52,9 @@ public class GeoPage<T> extends PageImpl<GeoResult<T>> {
* @param total
*/
public GeoPage(GeoResults<T> results, Pageable pageable, long total) {
super(results.getContent(), pageable, total);
this.averageDistance = results.getAverageDistance();
}

View File

@@ -73,7 +73,7 @@ public class GeoResult<T> {
return true;
}
if (obj == null || !getClass().isInstance(obj)) {
if (!(obj instanceof GeoResult)) {
return false;
}
@@ -90,8 +90,10 @@ public class GeoResult<T> {
public int hashCode() {
int result = 17;
result += 31 * distance.hashCode();
result += 31 * content.hashCode();
return result;
}

View File

@@ -45,6 +45,13 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
this(results, (Metric) null);
}
/**
* Creates a new {@link GeoResults} instance manually calculating the average distance in the given {@link Metric}
* from the distance values of the given {@link GeoResult}s.
*
* @param results must not be {@literal null}.
* @param metric must not be {@literal null}.
*/
public GeoResults(List<? extends GeoResult<T>> results, Metric metric) {
this(results, calculateAverageDistance(results, metric));
}
@@ -53,11 +60,13 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
* Creates a new {@link GeoResults} instance from the given {@link GeoResult}s and average distance.
*
* @param results must not be {@literal null}.
* @param averageDistance
* @param averageDistance can be {@literal null}.
*/
@PersistenceConstructor
public GeoResults(List<? extends GeoResult<T>> results, Distance averageDistance) {
Assert.notNull(results);
this.results = results;
this.averageDistance = averageDistance;
}
@@ -71,6 +80,15 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
return averageDistance;
}
/**
* Returns the actual content of the {@link GeoResults}.
*
* @return
*/
public List<GeoResult<T>> getContent() {
return Collections.unmodifiableList(results);
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
@@ -80,15 +98,6 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
return (Iterator<GeoResult<T>>) results.iterator();
}
/**
* Returns the actual
*
* @return
*/
public List<GeoResult<T>> getContent() {
return Collections.unmodifiableList(results);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
@@ -100,7 +109,7 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
return true;
}
if (obj == null || !getClass().isInstance(obj)) {
if (!(obj instanceof GeoResults)) {
return false;
}
@@ -115,9 +124,12 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * results.hashCode();
result += 31 * averageDistance.hashCode();
return result;
}

View File

@@ -29,6 +29,8 @@ public enum Metrics implements Metric {
private final double multiplier;
/**
* Creates a new {@link Metrics} using the given muliplier.
*
* @param multiplier the earth radius at equator.
*/
private Metrics(double multiplier) {

View File

@@ -56,49 +56,76 @@ public class Point {
this.y = point.y;
}
/**
* Returns the x-coordinate of the {@link Point}.
*
* @return
*/
public double getX() {
return x;
}
/**
* Returns the y-coordinate of the {@link Point}.
*
* @return
*/
public double getY() {
return y;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(x);
result = prime * result + (int) (temp ^ (temp >>> 32));
long temp = Double.doubleToLongBits(x);
result = 31 * result + (int) (temp ^ temp >>> 32);
temp = Double.doubleToLongBits(y);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + (int) (temp ^ temp >>> 32);
return result;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Point)) {
return false;
}
Point other = (Point) obj;
if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x)) {
return false;
}
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y)) {
return false;
}
return true;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("Point [latitude=%f, longitude=%f]", x, y);
return String.format("Point [x=%f, y=%f]", x, y);
}
}

View File

@@ -17,10 +17,13 @@ package org.springframework.data.geo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Simple value object to represent a {@link Polygon}.
@@ -36,49 +39,53 @@ public class Polygon implements Iterable<Point>, Shape {
/**
* Creates a new {@link Polygon} for the given Points.
*
* @param x
* @param y
* @param z
* @param x must not be {@literal null}.
* @param y must not be {@literal null}.
* @param z must not be {@literal null}.
* @param others
*/
public <P extends Point> Polygon(P x, P y, P z, P... others) {
public Polygon(Point x, Point y, Point z, Point... others) {
Assert.notNull(x);
Assert.notNull(y);
Assert.notNull(z);
Assert.notNull(x, "X coordinate must not be null!");
Assert.notNull(y, "Y coordinate must not be null!");
Assert.notNull(z, "Z coordinate must not be null!");
Assert.notNull(others);
this.points = new ArrayList<Point>(3 + others.length);
this.points.addAll(Arrays.asList(x, y, z));
this.points.addAll(Arrays.asList(others));
List<Point> points = new ArrayList<Point>(3 + others.length);
points.addAll(Arrays.asList(x, y, z));
points.addAll(Arrays.asList(others));
this.points = Collections.unmodifiableList(points);
}
/**
* Creates a new {@link Polygon} for the given Points.
*
* @param points
* @param points must not be {@literal null}.
*/
public <P extends Point> Polygon(List<P> points) {
@PersistenceConstructor
public Polygon(List<? extends Point> points) {
Assert.notNull(points);
this.points = new ArrayList<Point>(points.size());
List<Point> pointsToSet = new ArrayList<Point>(points.size());
for (Point point : points) {
Assert.notNull(point);
this.points.add(point);
pointsToSet.add(point);
}
this.points = Collections.unmodifiableList(pointsToSet);
}
/**
* Returns all {@link Point}s the {@link Polygon} is made of.
*
* @return
*/
public List<Point> getPoints() {
List<Point> result = new ArrayList<Point>();
for (Point point : points) {
result.add(point);
}
return result;
return this.points;
}
/*
@@ -100,7 +107,7 @@ public class Polygon implements Iterable<Point>, Shape {
return true;
}
if (obj == null || !(obj instanceof Polygon)) {
if (!(obj instanceof Polygon)) {
return false;
}
@@ -117,4 +124,13 @@ public class Polygon implements Iterable<Point>, Shape {
public int hashCode() {
return points.hashCode();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("Polygon: [%s]", StringUtils.collectionToCommaDelimitedString(points));
}
}

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.data.geo;
/**
* Common interface for all shapes. Allows building external representations of them.
*

View File

@@ -1,7 +1,8 @@
/**
* Support for reusable geospatial structures.
* Value types representing geo-spatial concepts.
*
* @author Thomas Darimont
* @author Oliver Gierke
* @since 1.8
*/
package org.springframework.data.geo;