A 100% pure Java library for the Twitter API with no extra dependency
Comprehensive search capabilities for tweets, users, and trending topics.
Search for tweets using keywords, hashtags, users, and advanced operators.
interface SearchResource {
/**
* Search for tweets matching query
* @param query Search query with parameters
* @return Search results with tweets and metadata
*/
QueryResult search(Query query) throws TwitterException;
}Usage Examples:
TwitterV1 v1 = twitter.v1();
// Simple text search
Query query = Query.of("Twitter API");
QueryResult result = v1.search().search(query);
for (Status tweet : result.getTweets()) {
System.out.println("@" + tweet.getUser().getScreenName() + ": " + tweet.getText());
}
// Advanced search with filters
Query advancedQuery = Query.of("java programming")
.lang("en")
.resultType(Query.ResultType.recent)
.count(100)
.since("2023-01-01")
.until("2023-12-31");
QueryResult advancedResult = v1.search().search(advancedQuery);Comprehensive query construction with filters and parameters.
class Query {
/**
* Create search query with search terms
* @param query Search terms and operators
* @return Query builder instance
*/
static Query of(String query);
/**
* Set language filter
* @param lang Language code (e.g., "en", "es", "fr")
* @return Query with language filter
*/
Query lang(String lang);
/**
* Set locale for query
* @param locale Locale string
* @return Query with locale setting
*/
Query locale(String locale);
/**
* Set maximum tweet ID (tweets older than this)
* @param maxId Maximum tweet ID
* @return Query with max ID filter
*/
Query maxId(long maxId);
/**
* Set number of results per page
* @param count Number of results (max 100)
* @return Query with count setting
*/
Query count(int count);
/**
* Set since date (YYYY-MM-DD format)
* @param since Start date for search
* @return Query with since date filter
*/
Query since(String since);
/**
* Set minimum tweet ID (tweets newer than this)
* @param sinceId Minimum tweet ID
* @return Query with since ID filter
*/
Query sinceId(long sinceId);
/**
* Set geocode filter for location-based search
* @param geocode "latitude,longitude,radius" (e.g., "37.781157,-122.398720,1mi")
* @return Query with geocode filter
*/
Query geocode(String geocode);
/**
* Set until date (YYYY-MM-DD format)
* @param until End date for search
* @return Query with until date filter
*/
Query until(String until);
/**
* Set result type filter
* @param resultType Type of results to return
* @return Query with result type filter
*/
Query resultType(ResultType resultType);
/**
* Get current query string
*/
String getQuery();
/**
* Get current language setting
*/
String getLang();
/**
* Get current count setting
*/
int getCount();
/**
* Get current max ID setting
*/
long getMaxId();
/**
* Get current since ID setting
*/
long getSinceId();
/**
* Result type enumeration
*/
enum ResultType {
/** Return most recent tweets */
recent,
/** Return most popular tweets */
popular,
/** Return mix of recent and popular */
mixed
}
}Advanced search operators for precise query construction:
// Exact phrase
Query.of("\"Twitter API\"");
// From specific user
Query.of("from:twitterapi");
// To specific user
Query.of("to:twitterapi");
// Mentioning user
Query.of("@twitterapi");
// Hashtags
Query.of("#TwitterAPI");
// URLs
Query.of("twitter.com");
// Positive sentiment
Query.of("Twitter :)");
// Negative sentiment
Query.of("Twitter :(");
// Question tweets
Query.of("Twitter ?");
// Retweets
Query.of("RT @twitterapi");
// Links
Query.of("Twitter filter:links");
// Images
Query.of("Twitter filter:images");
// Videos
Query.of("Twitter filter:videos");
// Media (images or videos)
Query.of("Twitter filter:media");
// Verified accounts only
Query.of("Twitter filter:verified");
// Exclude retweets
Query.of("Twitter -filter:retweets");
// Complex query combining operators
Query complexQuery = Query.of("(Twitter API OR \"Twitter4J\") from:twitterapi -filter:retweets filter:links")
.lang("en")
.resultType(Query.ResultType.recent);Search response with tweets and pagination metadata.
interface QueryResult extends TwitterResponse {
/**
* List of tweets matching search query
*/
List<Status> getTweets();
/**
* Whether there are more results available
*/
boolean hasNext();
/**
* Get next page of results
* @return Query for next page
*/
Query nextQuery();
/**
* Refresh search with same parameters
* @return Query for refresh
*/
Query refreshQuery();
/**
* Maximum tweet ID in results
*/
long getMaxId();
/**
* Minimum tweet ID in results
*/
long getSinceId();
/**
* Search completion time in seconds
*/
double getCompletedIn();
/**
* Number of tweets per page
*/
int getCount();
/**
* Search query string
*/
String getQuery();
}Pagination Example:
Query query = Query.of("Twitter API").count(100);
QueryResult result = v1.search().search(query);
// Process first page
for (Status tweet : result.getTweets()) {
processTweet(tweet);
}
// Get additional pages
while (result.hasNext()) {
Query nextQuery = result.nextQuery();
result = v1.search().search(nextQuery);
for (Status tweet : result.getTweets()) {
processTweet(tweet);
}
// Respect rate limits
RateLimitStatus rateLimit = result.getRateLimitStatus();
if (rateLimit.getRemaining() <= 1) {
Thread.sleep(rateLimit.getSecondsUntilReset() * 1000L);
}
}Access trending topics by location.
interface TrendsResources {
/**
* Get trending topics for a specific location
* @param woeid Where On Earth ID for location
* @return Trending topics for location
*/
Trends getPlaceTrends(int woeid) throws TwitterException;
/**
* Get available trend locations
* @return List of locations with trend data
*/
ResponseList<Location> getAvailableTrends() throws TwitterException;
/**
* Get closest trend locations to coordinates
* @param location Geographic coordinates
* @return List of nearby trend locations
*/
ResponseList<Location> getClosestTrends(GeoLocation location) throws TwitterException;
}Usage Examples:
// Get worldwide trends (WOEID = 1)
Trends worldTrends = v1.trends().getPlaceTrends(1);
for (Trend trend : worldTrends.getTrends()) {
System.out.println("#" + trend.getName() + " (" + trend.getTweetVolume() + " tweets)");
}
// Get trends for specific city (e.g., New York = 2459115)
Trends nyTrends = v1.trends().getPlaceTrends(2459115);
// Find available trend locations
ResponseList<Location> locations = v1.trends().getAvailableTrends();
for (Location loc : locations) {
System.out.println(loc.getName() + " (WOEID: " + loc.getWoeid() + ")");
}
// Find trends near coordinates
GeoLocation sanFrancisco = new GeoLocation(37.7749, -122.4194);
ResponseList<Location> nearbyLocations = v1.trends().getClosestTrends(sanFrancisco);interface Trends extends TwitterResponse {
/**
* Array of trending topics
*/
Trend[] getTrends();
/**
* Timestamp when trends were created
*/
LocalDateTime getCreatedAt();
/**
* Timestamp when trends are valid until
*/
LocalDateTime getAsOf();
/**
* Location information for trends
*/
Location[] getLocations();
}
interface Trend {
/**
* Trend name/hashtag
*/
String getName();
/**
* Trend search URL
*/
String getUrl();
/**
* Promoted content URL (if promoted)
*/
String getPromotedContent();
/**
* Search query for this trend
*/
String getQuery();
/**
* Estimated tweet volume (null if unavailable)
*/
Integer getTweetVolume();
}
interface Location {
/**
* Location name
*/
String getName();
/**
* Where On Earth ID
*/
int getWoeid();
/**
* Country name
*/
String getCountryName();
/**
* Country code
*/
String getCountryCode();
/**
* Parent location ID
*/
int getParentId();
/**
* Location type
*/
int getPlaceType();
/**
* Location URL
*/
String getUrl();
}public class SearchMonitor {
private final TwitterV1 v1;
private final String searchTerm;
private long lastSeenId = 1L;
public SearchMonitor(TwitterV1 v1, String searchTerm) {
this.v1 = v1;
this.searchTerm = searchTerm;
}
public List<Status> getNewTweets() throws TwitterException {
Query query = Query.of(searchTerm)
.sinceId(lastSeenId)
.count(100)
.resultType(Query.ResultType.recent);
QueryResult result = v1.search().search(query);
List<Status> newTweets = result.getTweets();
if (!newTweets.isEmpty()) {
lastSeenId = newTweets.get(0).getId();
}
return newTweets;
}
}public class HistoricalSearch {
public List<Status> searchDateRange(TwitterV1 v1, String query,
String startDate, String endDate) throws TwitterException {
List<Status> allTweets = new ArrayList<>();
Query searchQuery = Query.of(query)
.since(startDate)
.until(endDate)
.count(100)
.resultType(Query.ResultType.recent);
QueryResult result = v1.search().search(searchQuery);
allTweets.addAll(result.getTweets());
// Paginate through all results
while (result.hasNext()) {
result = v1.search().search(result.nextQuery());
allTweets.addAll(result.getTweets());
// Rate limit handling
RateLimitStatus rateLimit = result.getRateLimitStatus();
if (rateLimit.getRemaining() <= 1) {
try {
Thread.sleep(rateLimit.getSecondsUntilReset() * 1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
return allTweets;
}
}public class SearchAnalytics {
public SearchStats analyzeSearchResults(QueryResult result) {
List<Status> tweets = result.getTweets();
SearchStats stats = new SearchStats();
stats.totalTweets = tweets.size();
stats.retweetCount = (int) tweets.stream().filter(Status::isRetweet).count();
stats.originalTweetCount = stats.totalTweets - stats.retweetCount;
stats.averageRetweetCount = tweets.stream()
.mapToInt(Status::getRetweetCount)
.average().orElse(0.0);
stats.averageFavoriteCount = tweets.stream()
.mapToInt(Status::getFavoriteCount)
.average().orElse(0.0);
stats.topHashtags = tweets.stream()
.flatMap(tweet -> Arrays.stream(tweet.getHashtagEntities()))
.collect(Collectors.groupingBy(
HashtagEntity::getText,
Collectors.counting()
))
.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(10)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
return stats;
}
public static class SearchStats {
public int totalTweets;
public int retweetCount;
public int originalTweetCount;
public double averageRetweetCount;
public double averageFavoriteCount;
public Map<String, Long> topHashtags;
}
}
## Additional Utility Resources
### Saved Searches Management
Manage saved search queries for quick access to frequently used searches.
```java { .api }
interface SavedSearchesResources {
/**
* Get list of saved searches for authenticated user
* @return List of saved search queries
*/
ResponseList<SavedSearch> getSavedSearches() throws TwitterException;
/**
* Get details of a specific saved search
* @param id Saved search ID
* @return Saved search details
*/
SavedSearch showSavedSearch(long id) throws TwitterException;
/**
* Create a new saved search
* @param query Search query to save
* @return Created saved search
*/
SavedSearch createSavedSearch(String query) throws TwitterException;
/**
* Delete a saved search
* @param id Saved search ID to delete
* @return Deleted saved search
*/
SavedSearch destroySavedSearch(long id) throws TwitterException;
}
interface SavedSearch extends TwitterResponse {
/**
* Saved search unique identifier
*/
long getId();
/**
* Search query string
*/
String getQuery();
/**
* Display name for the saved search
*/
String getName();
/**
* Position/order of the saved search
*/
int getPosition();
/**
* Creation timestamp
*/
LocalDateTime getCreatedAt();
}Usage Examples:
TwitterV1 v1 = twitter.v1();
// Get all saved searches
ResponseList<SavedSearch> savedSearches = v1.savedSearches().getSavedSearches();
for (SavedSearch search : savedSearches) {
System.out.println(search.getName() + ": " + search.getQuery());
}
// Create new saved search
SavedSearch newSearch = v1.savedSearches().createSavedSearch("Twitter API");
System.out.println("Created saved search: " + newSearch.getId());
// Delete saved search
SavedSearch deleted = v1.savedSearches().destroySavedSearch(newSearch.getId());Report spam and block abusive users.
interface SpamReportingResource {
/**
* Report user as spam and block them
* @param screenName Screen name of user to report
* @return Reported and blocked user
*/
User reportSpam(String screenName) throws TwitterException;
/**
* Report user as spam and block them by user ID
* @param userId User ID to report
* @return Reported and blocked user
*/
User reportSpam(long userId) throws TwitterException;
}Usage Examples:
// Report spam user by screen name
User reportedUser = v1.spamReporting().reportSpam("spamaccount");
System.out.println("Reported and blocked: @" + reportedUser.getScreenName());
// Report spam user by ID
User reportedById = v1.spamReporting().reportSpam(123456789L);Access API configuration information and help resources.
interface HelpResources {
/**
* Get supported languages for Twitter
* @return List of supported language codes and names
*/
ResponseList<Language> getLanguages() throws TwitterException;
/**
* Get rate limit status for all endpoints
* @return Map of endpoint families to rate limit status
*/
Map<String, RateLimitStatus> getRateLimitStatus() throws TwitterException;
/**
* Get rate limit status for specific endpoint families
* @param resources Endpoint family names (e.g., "search", "statuses", "users")
* @return Map of specified families to rate limit status
*/
Map<String, RateLimitStatus> getRateLimitStatus(String... resources) throws TwitterException;
/**
* Get Twitter API configuration settings
* @return API configuration parameters
*/
TwitterAPIConfiguration getAPIConfiguration() throws TwitterException;
/**
* Get privacy policy information
* @return Privacy policy details
*/
String getPrivacyPolicy() throws TwitterException;
/**
* Get terms of service information
* @return Terms of service details
*/
String getTermsOfService() throws TwitterException;
}
interface Language {
/**
* Language code (e.g., "en", "es", "fr")
*/
String getCode();
/**
* Language name in native script
*/
String getName();
/**
* Language name in English
*/
String getLocalName();
/**
* Whether language is right-to-left
*/
boolean isRightToLeft();
}
interface TwitterAPIConfiguration {
/**
* Maximum characters allowed in tweet
*/
int getCharactersReservedPerMedia();
/**
* Maximum length of direct messages
*/
int getDmTextCharacterLimit();
/**
* Photo size configurations
*/
Map<String, PhotoSize> getPhotoSizes();
/**
* Maximum photo size in bytes
*/
long getPhotoSizeLimit();
/**
* Short URL length
*/
int getShortUrlLength();
/**
* HTTPS short URL length
*/
int getShortUrlLengthHttps();
}Usage Examples:
// Get supported languages
ResponseList<Language> languages = v1.help().getLanguages();
for (Language lang : languages) {
System.out.println(lang.getCode() + ": " + lang.getName());
}
// Check rate limits for specific endpoints
Map<String, RateLimitStatus> rateLimits = v1.help().getRateLimitStatus("search", "statuses");
for (Map.Entry<String, RateLimitStatus> entry : rateLimits.entrySet()) {
RateLimitStatus status = entry.getValue();
System.out.println(entry.getKey() + ": " + status.getRemaining() + "/" + status.getLimit());
}
// Get API configuration
TwitterAPIConfiguration config = v1.help().getAPIConfiguration();
System.out.println("Tweet character limit: " + config.getCharactersReservedPerMedia());
System.out.println("DM character limit: " + config.getDmTextCharacterLimit());Install with Tessl CLI
npx tessl i tessl/maven-org-twitter4j--twitter4j-core