A 100% pure Java library for the Twitter API with no extra dependency
Location-based functionality including places, geocoding, and geographic search.
Search for places and geographic locations.
interface PlacesGeoResources {
/**
* Search for places matching query
* @param query Geographic query with location and search parameters
* @return List of matching places
*/
ResponseList<Place> searchPlaces(GeoQuery query) throws TwitterException;
/**
* Find similar places to a location
* @param location Geographic coordinates
* @param name Place name to search for
* @param containedWithin Place ID that should contain the result
* @param streetAddress Street address for more precise matching
* @return List of similar places
*/
ResponseList<Place> getSimilarPlaces(GeoLocation location, String name,
String containedWithin, String streetAddress) throws TwitterException;
/**
* Reverse geocoding - find places near coordinates
* @param query Geographic query with coordinates
* @return List of places near the coordinates
*/
ResponseList<Place> reverseGeoCode(GeoQuery query) throws TwitterException;
/**
* Get detailed information about a specific place
* @param placeId Twitter place ID
* @return Detailed place information
*/
Place getGeoDetails(String placeId) throws TwitterException;
}Usage Examples:
TwitterV1 v1 = twitter.v1();
// Search for places by name
GeoQuery query = GeoQuery.of("San Francisco")
.accuracy(GeoQuery.Accuracy.city)
.granularity("city")
.maxResults(10);
ResponseList<Place> places = v1.placesGeo().searchPlaces(query);
for (Place place : places) {
System.out.println(place.getFullName() + " (" + place.getId() + ")");
}
// Reverse geocoding - find places near coordinates
GeoLocation sanFrancisco = new GeoLocation(37.7749, -122.4194);
GeoQuery reverseQuery = GeoQuery.of(sanFrancisco)
.accuracy("1km")
.granularity("neighborhood");
ResponseList<Place> nearbyPlaces = v1.placesGeo().reverseGeoCode(reverseQuery);
for (Place place : nearbyPlaces) {
System.out.println("Nearby: " + place.getName());
}
// Get details for a specific place
Place placeDetails = v1.placesGeo().getGeoDetails("5a110d312052166f");
System.out.println("Full name: " + placeDetails.getFullName());
System.out.println("Country: " + placeDetails.getCountry());
System.out.println("Place type: " + placeDetails.getPlaceType());Construct geographic search queries with location and filtering parameters.
class GeoQuery {
/**
* Create query with place name
* @param query Place name or address to search for
* @return GeoQuery with search term
*/
static GeoQuery of(String query);
/**
* Create query with coordinates
* @param location Geographic coordinates
* @return GeoQuery with location
*/
static GeoQuery of(GeoLocation location);
/**
* Create query with coordinates and IP address
* @param location Geographic coordinates
* @param ip IP address for additional context
* @return GeoQuery with location and IP
*/
static GeoQuery of(GeoLocation location, String ip);
/**
* Set search accuracy
* @param accuracy Accuracy level or distance (e.g., "1km", "5mi")
* @return GeoQuery with accuracy setting
*/
GeoQuery accuracy(String accuracy);
/**
* Set search accuracy using predefined levels
* @param accuracy Predefined accuracy level
* @return GeoQuery with accuracy setting
*/
GeoQuery accuracy(Accuracy accuracy);
/**
* Set place granularity
* @param granularity Granularity level ("poi", "neighborhood", "city", "admin", "country")
* @return GeoQuery with granularity setting
*/
GeoQuery granularity(String granularity);
/**
* Set maximum number of results
* @param maxResults Maximum number of places to return
* @return GeoQuery with max results setting
*/
GeoQuery maxResults(int maxResults);
/**
* Set contained within constraint
* @param containedWithin Place ID that should contain results
* @return GeoQuery with containment constraint
*/
GeoQuery containedWithin(String containedWithin);
/**
* Set street address for more precise matching
* @param streetAddress Street address
* @return GeoQuery with address constraint
*/
GeoQuery streetAddress(String streetAddress);
/**
* Predefined accuracy levels
*/
enum Accuracy {
/** Point of interest level */
poi,
/** Neighborhood level */
neighborhood,
/** City level */
city,
/** Administrative level */
admin,
/** Country level */
country
}
}Represent geographic coordinates.
class GeoLocation {
/**
* Create location with latitude and longitude
* @param latitude Latitude in decimal degrees
* @param longitude Longitude in decimal degrees
*/
GeoLocation(double latitude, double longitude);
/**
* Get latitude
* @return Latitude in decimal degrees
*/
double getLatitude();
/**
* Get longitude
* @return Longitude in decimal degrees
*/
double getLongitude();
/**
* Calculate distance to another location
* @param other Other location
* @return Distance in kilometers
*/
double distanceTo(GeoLocation other);
/**
* Get string representation in "lat,lon" format
*/
@Override
String toString();
}Geographic Query Examples:
// Search for coffee shops in New York
GeoQuery coffeeQuery = GeoQuery.of("coffee")
.containedWithin("01a9a39529b27f36") // New York City place ID
.granularity("poi")
.maxResults(20);
ResponseList<Place> coffeeShops = v1.placesGeo().searchPlaces(coffeeQuery);
// Find neighborhoods within 2km of coordinates
GeoLocation myLocation = new GeoLocation(40.7128, -74.0060);
GeoQuery neighborhoodQuery = GeoQuery.of(myLocation)
.accuracy("2km")
.granularity("neighborhood");
ResponseList<Place> neighborhoods = v1.placesGeo().reverseGeoCode(neighborhoodQuery);
// Search for places with specific address
GeoQuery addressQuery = GeoQuery.of("Twitter HQ")
.streetAddress("1355 Market St, San Francisco, CA")
.granularity("poi");
ResponseList<Place> locations = v1.placesGeo().searchPlaces(addressQuery);Complete place information and geographic metadata.
interface Place extends TwitterResponse {
/**
* Unique place identifier
*/
String getId();
/**
* Place name
*/
String getName();
/**
* Full place name (includes parent places)
*/
String getFullName();
/**
* Country where place is located
*/
String getCountry();
/**
* Country code (ISO 3166-1 alpha-2)
*/
String getCountryCode();
/**
* Place type ("poi", "neighborhood", "city", "admin", "country")
*/
String getPlaceType();
/**
* URL for place information
*/
String getURL();
/**
* Geographic bounding box for place
* @return Array of coordinate pairs defining the bounding box
*/
GeoLocation[][] getBoundingBoxCoordinates();
/**
* Bounding box type (usually "Polygon")
*/
String getBoundingBoxType();
/**
* Places that contain this place
* @return Array of parent/containing places
*/
Place[] getContainedWithin();
/**
* Additional place attributes
* @return Map of attribute keys to values
*/
Map<String, String> getAttributes();
/**
* Street address (if available)
*/
String getStreetAddress();
/**
* Locality/city name
*/
String getLocality();
/**
* Administrative region (state/province)
*/
String getRegion();
/**
* ISO country code
*/
String getIso3();
/**
* Postal code
*/
String getPostalCode();
/**
* Phone number (if available)
*/
String getPhone();
/**
* Twitter handle (if place has associated account)
*/
String getTwitter();
/**
* App ID that created this place (if applicable)
*/
String getAppId();
}Add location information to tweets.
// Create status update with location
GeoLocation tweetLocation = new GeoLocation(37.7749, -122.4194);
StatusUpdate statusWithLocation = StatusUpdate.of("Tweeting from San Francisco!")
.location(tweetLocation)
.displayCoordinates(true)
.placeId("5a110d312052166f"); // San Francisco place ID
Status geoTaggedTweet = v1.tweets().updateStatus(statusWithLocation);
System.out.println("Tweet location: " + geoTaggedTweet.getGeoLocation());
System.out.println("Tweet place: " + geoTaggedTweet.getPlace().getFullName());Search for tweets near specific locations.
// Search for tweets near San Francisco
GeoLocation sf = new GeoLocation(37.7749, -122.4194);
String geocode = sf.getLatitude() + "," + sf.getLongitude() + ",10km";
Query locationQuery = Query.of("food")
.geocode(geocode)
.count(100);
QueryResult results = v1.search().search(locationQuery);
for (Status tweet : results.getTweets()) {
if (tweet.getGeoLocation() != null) {
System.out.println("@" + tweet.getUser().getScreenName() + " from " +
tweet.getGeoLocation().toString() + ": " + tweet.getText());
}
if (tweet.getPlace() != null) {
System.out.println("Place: " + tweet.getPlace().getFullName());
}
}public class PlaceHierarchy {
private final TwitterV1 v1;
public List<Place> getPlaceHierarchy(String placeId) throws TwitterException {
List<Place> hierarchy = new ArrayList<>();
Place currentPlace = v1.placesGeo().getGeoDetails(placeId);
hierarchy.add(currentPlace);
// Walk up the containment hierarchy
while (currentPlace.getContainedWithin() != null &&
currentPlace.getContainedWithin().length > 0) {
Place parent = currentPlace.getContainedWithin()[0];
hierarchy.add(parent);
// Get full details for parent
currentPlace = v1.placesGeo().getGeoDetails(parent.getId());
}
return hierarchy;
}
public void printPlaceHierarchy(String placeId) throws TwitterException {
List<Place> hierarchy = getPlaceHierarchy(placeId);
System.out.println("Place hierarchy (specific to general):");
for (int i = 0; i < hierarchy.size(); i++) {
Place place = hierarchy.get(i);
String indent = " ".repeat(i);
System.out.println(indent + place.getName() + " (" + place.getPlaceType() + ")");
}
}
}public class GeoBoundingBox {
public static boolean isLocationInPlace(GeoLocation location, Place place) {
GeoLocation[][] boundingBox = place.getBoundingBoxCoordinates();
if (boundingBox == null || boundingBox.length == 0) {
return false;
}
// Simple bounding box check (assumes rectangular box)
GeoLocation[] box = boundingBox[0];
if (box.length < 2) return false;
double minLat = Math.min(box[0].getLatitude(), box[1].getLatitude());
double maxLat = Math.max(box[0].getLatitude(), box[1].getLatitude());
double minLon = Math.min(box[0].getLongitude(), box[1].getLongitude());
double maxLon = Math.max(box[0].getLongitude(), box[1].getLongitude());
return location.getLatitude() >= minLat && location.getLatitude() <= maxLat &&
location.getLongitude() >= minLon && location.getLongitude() <= maxLon;
}
public static GeoLocation getBoundingBoxCenter(Place place) {
GeoLocation[][] boundingBox = place.getBoundingBoxCoordinates();
if (boundingBox == null || boundingBox.length == 0) {
return null;
}
GeoLocation[] box = boundingBox[0];
if (box.length < 2) return null;
double centerLat = (box[0].getLatitude() + box[1].getLatitude()) / 2;
double centerLon = (box[0].getLongitude() + box[1].getLongitude()) / 2;
return new GeoLocation(centerLat, centerLon);
}
}public class LocationAnalytics {
private final TwitterV1 v1;
public Map<String, Integer> analyzeTweetsByLocation(String searchQuery,
GeoLocation center,
String radius) throws TwitterException {
String geocode = center.getLatitude() + "," + center.getLongitude() + "," + radius;
Query query = Query.of(searchQuery)
.geocode(geocode)
.count(100)
.resultType(Query.ResultType.recent);
QueryResult results = v1.search().search(query);
Map<String, Integer> locationCounts = new HashMap<>();
for (Status tweet : results.getTweets()) {
String location = "Unknown";
if (tweet.getPlace() != null) {
location = tweet.getPlace().getFullName();
} else if (tweet.getUser().getLocation() != null &&
!tweet.getUser().getLocation().trim().isEmpty()) {
location = tweet.getUser().getLocation();
}
locationCounts.merge(location, 1, Integer::sum);
}
return locationCounts.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
}
public List<Place> findPopularPlacesNear(GeoLocation location, String radius)
throws TwitterException {
GeoQuery query = GeoQuery.of(location)
.accuracy(radius)
.granularity("poi")
.maxResults(50);
ResponseList<Place> places = v1.placesGeo().reverseGeoCode(query);
// Sort by some popularity metric (you might need additional data)
return places.stream()
.sorted((p1, p2) -> p1.getName().compareTo(p2.getName()))
.collect(Collectors.toList());
}
}Common geographic API errors and handling:
try {
GeoQuery query = GeoQuery.of("Unknown Place Name");
ResponseList<Place> places = v1.placesGeo().searchPlaces(query);
if (places.isEmpty()) {
System.out.println("No places found matching the query");
}
} catch (TwitterException e) {
switch (e.getStatusCode()) {
case 400:
System.out.println("Invalid geographic query parameters");
break;
case 404:
System.out.println("Place not found");
break;
case 429:
System.out.println("Rate limit exceeded for geo API");
break;
default:
System.out.println("Geo API error: " + e.getMessage());
}
}
try {
Place place = v1.placesGeo().getGeoDetails("invalid_place_id");
} catch (TwitterException e) {
if (e.getStatusCode() == 404) {
System.out.println("Place ID does not exist");
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-twitter4j--twitter4j-core