diff --git a/function/spring-twitter-function/README.adoc b/function/spring-twitter-function/README.adoc
index 1427a796..26cd6c56 100644
--- a/function/spring-twitter-function/README.adoc
+++ b/function/spring-twitter-function/README.adoc
@@ -2,34 +2,31 @@
This module provides couple of twitter functions that can be reused and composed in other applications.
-To use those functions add the following dependency to your POM:
+This module exposes auto-configurations for the following beans:
-[source,XML]
-----
-
- org.springframework.cloud.fn
- twitter-function
- ${java-functions.version}
-
-----
+* `twitterTrendFunction`
+* `twitterUsersFunction`
+* `twitterGeoFunction`
+
+Each of them are conditional by specific configuration properties.
## 1. Twitter Trend Function
-Functions can return either Trends topics or the Locations of the trending topics. The `twitter.trend.trend-query-type` property allows choosing between both types.
+Function can return either Trends topics or the Locations of the trending topics.
+The `twitter.trend.trend-query-type` property allows choosing between both types.
+This property is required to enable the function auto-configuration.
-* Trends - `twitter.trend.trend-query-type` is set to `trend`. Leverages the https://developer.twitter.com/en/docs/trends/trends-for-location/api-reference/get-trends-place[Trends API] to return the https://help.twitter.com/en/using-twitter/twitter-trending-faqs[trending topics] near a specific latitude, longitude location.
+* Trends - `twitter.trend.trend-query-type` is set to `trend`.
+Leverages the https://developer.twitter.com/en/docs/trends/trends-for-location/api-reference/get-trends-place[Trends API] to return the https://help.twitter.com/en/using-twitter/twitter-trending-faqs[trending topics] near a specific latitude, longitude location.
-* Trend Locations - the `twitter.trend.trend-query-type` is set `trendLocation`. Retrieve a full or nearby locations list of trending topics by location. If the `latitude`, `longitude` parameters are NOT provided the processor performs the https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-available[Trends Available API] and returns the locations that Twitter has trending topic information for.
+* Trend Locations - the `twitter.trend.trend-query-type` is set `trendLocation`.
+Retrieve a full or nearby locations list of trending topics by location. If the `latitude`, `longitude` parameters are NOT provided the processor performs the https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-available[Trends Available API] and returns the locations that Twitter has trending topic information for.
If the `latitude`, `longitude` parameters are provided the processor performs the https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-closest[Trends Closest API] and returns the locations that Twitter has trending topic information for, closest to a specified location.
Response is an array of `locations` that encode the location's WOEID and some other human-readable information such as a canonical name and country the location belongs in.
### 1.1 Beans for injection
-You can import the `TwitterTrendFunctionConfiguration` in a Spring Boot application and then inject the following bean.
-
-`filterFunction`
-
You can use `Function, Message> twitterTrendFunction` as a qualifier when injecting.
Once injected, you can use the `apply` method of the `Function` to invoke it and get the result.
@@ -45,12 +42,11 @@ See this link:src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTr
### 1.4 Other usage
-Leveraging the Spring Cloud Function composability, you can compose the Trend function in your boot app like this:
+Leveraging the Spring Cloud Function "composability", you can compose the Trend function in your boot app like this:
[source,Java]
----
@SpringBootApplication
-@Import(TwitterTrendFunctionConfiguration.class )
public class MyTwitterTrendBootApp {
public static void main(String[] args) {
@@ -79,12 +75,10 @@ Some parameters in this method are only required based on the existence of other
NOTE: Limits: 15 requests / 15-min window (user auth).
+This function auto-configuration is conditional on `twitter.geo.search.ip != null || (twitter.geo.location.lat != null && twitter.geo.location.lon != null)`
+
### 2.1 Beans for injection
-You can import the `TwitterGeoFunctionConfiguration` in a Spring Boot application and then inject the following bean.
-
-`filterFunction`
-
You can use `Function, Message> twitterGeoFunction` as a qualifier when injecting.
Once injected, you can use the `apply` method of the `Function` to invoke it and get the result.
@@ -96,7 +90,7 @@ For more information on the various options available, please see link:../twitte
### 2.3 Tests
-See this link:src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTest.java[test suite] for examples of how this function is used.
+See this link:src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTests.java[test suite] for examples of how this function is used.
### 2.4 Other usage
@@ -105,7 +99,6 @@ Leveraging the Spring Cloud Function composability, you can compose the Geo func
[source,Java]
----
@SpringBootApplication
-@Import(TwitterGeoFunctionConfiguration.class )
public class MyTwitterGeoProcessorBootApp {
public static void main(String[] args) {
@@ -122,6 +115,7 @@ Uses SpEL expressions to compute the query parameters from the input message.
Use the single quoted literals to set static values (e.g. user-id: '6666, 9999, 10000').
Use `twitter.users.type` property allow to select the query approaches.
+This property is required to trigger the `twitterUsersFunction` auto-configuration.
* https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-lookup[Users Lookup API] - Returns fully-hydrated user objects for up to 100 users per request, as specified by comma-separated values passed to the `userId` and/or `screenName` parameters. Rate limits: (300 requests / 15-min window)
* https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-search[Users Search API] - Relevance-based search interface to public user accounts on Twitter.
@@ -129,10 +123,6 @@ Querying by topical interest, full name, company name, location, or other criter
### 3.1 Beans for injection
-You can import the `TwitterUsersFunctionConfiguration` in a Spring Boot application and then inject the following bean.
-
-`filterFunction`
-
You can use `Function, Message> twitterUsersFunction` as a qualifier when injecting.
Once injected, you can use the `apply` method of the `Function` to invoke it and get the result.
diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionConfiguration.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionConfiguration.java
index 7529aa6a..0664b6e6 100644
--- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionConfiguration.java
+++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,27 +27,29 @@ import twitter4j.Place;
import twitter4j.Twitter;
import twitter4j.TwitterException;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.fn.common.twitter.TwitterConnectionConfiguration;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
import org.springframework.messaging.Message;
/**
+ * Auto-configuration for Twitter Geo function.
+ *
* @author Christian Tzolov
*/
-@Configuration
+@ConditionalOnExpression("environment['twitter.geo.search.ip'] != null || (environment['twitter.geo.location.lat'] != null && environment['twitter.geo.location.lon'] != null)")
+@AutoConfiguration(after = TwitterConnectionConfiguration.class)
@EnableConfigurationProperties(TwitterGeoFunctionProperties.class)
-@Import(TwitterConnectionConfiguration.class)
public class TwitterGeoFunctionConfiguration {
- private static final Log logger = LogFactory.getLog(TwitterGeoFunctionConfiguration.class);
+ private static final Log LOGGER = LogFactory.getLog(TwitterGeoFunctionConfiguration.class);
@Bean
public Function, GeoQuery> messageToGeoQueryFunction(TwitterGeoFunctionProperties geoProperties) {
- return message -> {
+ return (message) -> {
String ip = null;
if (geoProperties.getSearch().getIp() != null) {
ip = geoProperties.getSearch().getIp().getValue(message, String.class);
@@ -76,12 +78,12 @@ public class TwitterGeoFunctionConfiguration {
@Bean
@ConditionalOnProperty(name = "twitter.geo.search.type", havingValue = "search", matchIfMissing = true)
public Function> twitterSearchPlacesFunction(Twitter twitter) {
- return geoQuery -> {
+ return (geoQuery) -> {
try {
return twitter.searchPlaces(geoQuery);
}
- catch (TwitterException e) {
- logger.error("Places Search failed!", e);
+ catch (TwitterException ex) {
+ LOGGER.error("Places Search failed!", ex);
}
return null;
};
@@ -90,12 +92,12 @@ public class TwitterGeoFunctionConfiguration {
@Bean
@ConditionalOnProperty(name = "twitter.geo.search.type", havingValue = "reverse")
public Function> twitterReverseGeocodeFunction(Twitter twitter) {
- return geoQuery -> {
+ return (geoQuery) -> {
try {
return twitter.reverseGeoCode(geoQuery);
}
- catch (TwitterException e) {
- logger.error("Reverse Geocode failed!", e);
+ catch (TwitterException ex) {
+ LOGGER.error("Reverse Geocode failed!", ex);
}
return null;
};
@@ -105,7 +107,7 @@ public class TwitterGeoFunctionConfiguration {
public Function, Message> twitterGeoFunction(Function, GeoQuery> toGeoQuery,
Function> places, Function> managedJson) {
- return toGeoQuery.andThen(places).andThen(managedJson)::apply;
+ return toGeoQuery.andThen(places).andThen(managedJson);
}
}
diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionProperties.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionProperties.java
index cf316d27..1c5ff0a1 100644
--- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionProperties.java
+++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,18 +21,17 @@ import jakarta.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.expression.Expression;
-import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.validation.annotation.Validated;
/**
+ * Configuration properties for Twitter Geo function.
+ *
* @author Christian Tzolov
*/
@ConfigurationProperties("twitter.geo")
@Validated
public class TwitterGeoFunctionProperties {
- private static final Expression DEFAULT_EXPRESSION = new SpelExpressionParser().parseExpression("payload");
-
public enum GeoType {
/** Geo retrieval type. */
@@ -51,9 +50,6 @@ public class TwitterGeoFunctionProperties {
*/
private Search search = new Search();
- /**
- *
- */
private Location location = new Location();
/**
@@ -68,7 +64,7 @@ public class TwitterGeoFunctionProperties {
* in meters, but it can also take a string that is suffixed with ft to specify feet.
* If this is not passed in, then it is assumed to be 0m. If coming from a device, in
* practice, this value is whatever accuracy the device has measuring its location
- * (whether it be coming from a GPS, WiFi triangulation, etc.).
+ * (whether it be coming from a GPS, Wi-Fi triangulation, etc.).
*/
private String accuracy = null;
@@ -79,7 +75,7 @@ public class TwitterGeoFunctionProperties {
private String granularity = null;
public Search getSearch() {
- return search;
+ return this.search;
}
public void setSearch(Search search) {
@@ -87,7 +83,7 @@ public class TwitterGeoFunctionProperties {
}
public GeoType getType() {
- return type;
+ return this.type;
}
public void setType(GeoType type) {
@@ -95,7 +91,7 @@ public class TwitterGeoFunctionProperties {
}
public Location getLocation() {
- return location;
+ return this.location;
}
public void setLocation(Location location) {
@@ -103,7 +99,7 @@ public class TwitterGeoFunctionProperties {
}
public int getMaxResults() {
- return maxResults;
+ return this.maxResults;
}
public void setMaxResults(int maxResults) {
@@ -111,7 +107,7 @@ public class TwitterGeoFunctionProperties {
}
public String getAccuracy() {
- return accuracy;
+ return this.accuracy;
}
public void setAccuracy(String accuracy) {
@@ -119,7 +115,7 @@ public class TwitterGeoFunctionProperties {
}
public String getGranularity() {
- return granularity;
+ return this.granularity;
}
public void setGranularity(String granularity) {
@@ -128,13 +124,12 @@ public class TwitterGeoFunctionProperties {
@AssertTrue(message = "Either the IP or the Location must be set")
public boolean isAtLeastOne() {
- return this.getSearch().getIp() == null
- ^ (this.getLocation().getLat() == null && this.getLocation().getLon() == null);
+ return getSearch().getIp() == null ^ (getLocation().getLat() == null && getLocation().getLon() == null);
}
@AssertTrue(message = "The IP parameter is applicable only for 'Search' GeoType")
public boolean isIpUsedWithSearchGeoType() {
- if (this.getSearch().getIp() != null) {
+ if (getSearch().getIp() != null) {
return this.type == GeoType.search;
}
return true;
@@ -154,7 +149,7 @@ public class TwitterGeoFunctionProperties {
private Expression query = null;
public Expression getIp() {
- return ip;
+ return this.ip;
}
public void setIp(Expression ip) {
@@ -162,7 +157,7 @@ public class TwitterGeoFunctionProperties {
}
public Expression getQuery() {
- return query;
+ return this.query;
}
public void setQuery(Expression query) {
@@ -184,7 +179,7 @@ public class TwitterGeoFunctionProperties {
private Expression lon;
public Expression getLat() {
- return lat;
+ return this.lat;
}
public void setLat(Expression lat) {
@@ -192,7 +187,7 @@ public class TwitterGeoFunctionProperties {
}
public Expression getLon() {
- return lon;
+ return this.lon;
}
public void setLon(Expression lon) {
diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/package-info.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/package-info.java
new file mode 100644
index 00000000..4e945ae5
--- /dev/null
+++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The Twitter Geo function auto-configuration.
+ */
+package org.springframework.cloud.fn.twitter.geo;
diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionConfiguration.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionConfiguration.java
index 236e85c6..6f2f5705 100644
--- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionConfiguration.java
+++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,32 +27,34 @@ import twitter4j.Trends;
import twitter4j.Twitter;
import twitter4j.TwitterException;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.fn.common.twitter.TwitterConnectionConfiguration;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
import org.springframework.messaging.Message;
/**
+ * Auto-configuration for Twitter Trend function.
+ *
* @author Christian Tzolov
*/
-@Configuration
+@ConditionalOnProperty(prefix = "twitter.trend", name = "trend-query-type")
+@AutoConfiguration(after = TwitterConnectionConfiguration.class)
@EnableConfigurationProperties(TwitterTrendFunctionProperties.class)
-@Import(TwitterConnectionConfiguration.class)
public class TwitterTrendFunctionConfiguration {
- private static final Log logger = LogFactory.getLog(TwitterTrendFunctionConfiguration.class);
+ private static final Log LOGGER = LogFactory.getLog(TwitterTrendFunctionConfiguration.class);
@Bean
public Function, Trends> trend(TwitterTrendFunctionProperties properties, Twitter twitter) {
- return message -> {
+ return (message) -> {
try {
int woeid = properties.getLocationId().getValue(message, int.class);
return twitter.getPlaceTrends(woeid);
}
- catch (TwitterException e) {
- logger.error("Twitter API error!", e);
+ catch (TwitterException ex) {
+ LOGGER.error("Twitter API error!", ex);
}
return null;
};
@@ -61,7 +63,8 @@ public class TwitterTrendFunctionConfiguration {
@Bean
public Function, List> closestOrAvailableTrends(TwitterTrendFunctionProperties properties,
Twitter twitter) {
- return message -> {
+
+ return (message) -> {
try {
if (properties.getClosest().getLat() != null && properties.getClosest().getLon() != null) {
double lat = properties.getClosest().getLat().getValue(message, double.class);
@@ -72,8 +75,8 @@ public class TwitterTrendFunctionConfiguration {
return twitter.getAvailableTrends();
}
}
- catch (TwitterException e) {
- logger.error("Twitter API error!", e);
+ catch (TwitterException ex) {
+ LOGGER.error("Twitter API error!", ex);
}
return null;
};
diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionProperties.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionProperties.java
index 63cadcd0..5f944c92 100644
--- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionProperties.java
+++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,19 +20,22 @@ import jakarta.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.expression.Expression;
-import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.integration.expression.FunctionExpression;
+import org.springframework.messaging.Message;
import org.springframework.validation.annotation.Validated;
/**
+ * Configuration properties for Twitter Trend function.
+ *
* @author Christian Tzolov
*/
@ConfigurationProperties("twitter.trend")
@Validated
public class TwitterTrendFunctionProperties {
- private static final Expression DEFAULT_EXPRESSION = new SpelExpressionParser().parseExpression("payload");
+ private static final Expression DEFAULT_EXPRESSION = new FunctionExpression>(Message::getPayload);
- enum TrendQueryType {
+ public enum TrendQueryType {
/** Retrieve trending places. */
trend,
@@ -41,10 +44,10 @@ public class TwitterTrendFunctionProperties {
}
- private TrendQueryType trendQueryType = TrendQueryType.trend;
+ private TrendQueryType trendQueryType;
public TrendQueryType getTrendQueryType() {
- return trendQueryType;
+ return this.trendQueryType;
}
public void setTrendQueryType(TrendQueryType trendQueryType) {
@@ -59,40 +62,39 @@ public class TwitterTrendFunctionProperties {
private Expression locationId = DEFAULT_EXPRESSION;
public Expression getLocationId() {
- return locationId;
+ return this.locationId;
}
public void setLocationId(Expression locationId) {
this.locationId = locationId;
}
- /**
- *
- */
- private Closest closest = new Closest();
+ private final Closest closest = new Closest();
public Closest getClosest() {
- return closest;
+ return this.closest;
}
public static class Closest {
/**
* If provided with a long parameter the available trend locations will be sorted
- * by distance, nearest to furthest, to the co-ordinate pair. The valid ranges for
- * longitude is -180.0 to +180.0 (West is negative, East is positive) inclusive.
+ * by distance, nearest to the furthest, to the co-ordinate pair. The valid ranges
+ * for longitude is -180.0 to +180.0 (West is negative, East is positive)
+ * inclusive.
*/
private Expression lat;
/**
* If provided with a lat parameter the available trend locations will be sorted
- * by distance, nearest to furthest, to the co-ordinate pair. The valid ranges for
- * longitude is -180.0 to +180.0 (West is negative, East is positive) inclusive.
+ * by distance, nearest to the furthest, to the co-ordinate pair. The valid ranges
+ * for longitude is -180.0 to +180.0 (West is negative, East is positive)
+ * inclusive.
*/
private Expression lon;
public Expression getLat() {
- return lat;
+ return this.lat;
}
public void setLat(Expression lat) {
@@ -100,7 +102,7 @@ public class TwitterTrendFunctionProperties {
}
public Expression getLon() {
- return lon;
+ return this.lon;
}
public void setLon(Expression lon) {
diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/package-info.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/package-info.java
new file mode 100644
index 00000000..9ab3f542
--- /dev/null
+++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The Twitter Trend function auto-configuration.
+ */
+package org.springframework.cloud.fn.twitter.trend;
diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionConfiguration.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionConfiguration.java
index 7dd4ed09..634a683f 100644
--- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionConfiguration.java
+++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,41 +21,40 @@ import java.util.function.Function;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import twitter4j.ResponseList;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.User;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.fn.common.twitter.TwitterConnectionConfiguration;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
import org.springframework.messaging.Message;
/**
+ * Auto-configuration for Twitter Users function.
+ *
* @author Christian Tzolov
*/
-@Configuration
+@ConditionalOnProperty(prefix = "twitter.users", name = "type")
+@AutoConfiguration(after = TwitterConnectionConfiguration.class)
@EnableConfigurationProperties(TwitterUsersFunctionProperties.class)
-@Import(TwitterConnectionConfiguration.class)
public class TwitterUsersFunctionConfiguration {
- private static final Log logger = LogFactory.getLog(TwitterUsersFunctionConfiguration.class);
+ private static final Log LOGGER = LogFactory.getLog(TwitterUsersFunctionConfiguration.class);
@Bean
@ConditionalOnProperty(name = "twitter.users.type", havingValue = "search")
public Function, List> userSearch(Twitter twitter, TwitterUsersFunctionProperties properties) {
- return message -> {
+ return (message) -> {
String query = properties.getSearch().getQuery().getValue(message, String.class);
try {
- ResponseList users = twitter.searchUsers(query, properties.getSearch().getPage());
- return users;
+ return twitter.searchUsers(query, properties.getSearch().getPage());
}
- catch (TwitterException e) {
- logger.error("Twitter API error!", e);
+ catch (TwitterException ex) {
+ LOGGER.error("Twitter API error!", ex);
}
return null;
};
@@ -65,7 +64,7 @@ public class TwitterUsersFunctionConfiguration {
@ConditionalOnProperty(name = "twitter.users.type", havingValue = "lookup")
public Function, List> userLookup(Twitter twitter, TwitterUsersFunctionProperties properties) {
- return message -> {
+ return (message) -> {
try {
TwitterUsersFunctionProperties.Lookup lookup = properties.getLookup();
@@ -78,20 +77,17 @@ public class TwitterUsersFunctionConfiguration {
return twitter.lookupUsers(ids);
}
}
- catch (TwitterException e) {
- logger.error("Twitter API error!", e);
+ catch (TwitterException ex) {
+ LOGGER.error("Twitter API error!", ex);
}
return null;
};
}
@Bean
- /**
- * queryUsers - depends on the `twitter.users.type` property is either userSearch or
- * userLookup. managedJson - converts Users into JSON message payload.
- */
public Function, Message> twitterUsersFunction(Function, List> queryUsers,
Function> managedJson) {
+
return queryUsers.andThen(managedJson);
}
diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionProperties.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionProperties.java
index 75243026..fd865dc2 100644
--- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionProperties.java
+++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,21 +17,23 @@
package org.springframework.cloud.fn.twitter.users;
import jakarta.validation.constraints.AssertTrue;
-import jakarta.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.expression.Expression;
-import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.integration.expression.FunctionExpression;
+import org.springframework.messaging.Message;
import org.springframework.validation.annotation.Validated;
/**
+ * Configuration properties for Twitter Users function.
+ *
* @author Christian Tzolov
*/
@ConfigurationProperties("twitter.users")
@Validated
public class TwitterUsersFunctionProperties {
- private static final Expression DEFAULT_EXPRESSION = new SpelExpressionParser().parseExpression("payload");
+ private static final Expression DEFAULT_EXPRESSION = new FunctionExpression>(Message::getPayload);
public enum UserQueryType {
@@ -43,8 +45,7 @@ public class TwitterUsersFunctionProperties {
/**
* Perform search or lookup type of search.
*/
- @NotNull
- private UserQueryType type = UserQueryType.search;
+ private UserQueryType type;
/**
* Returns fully-hydrated user objects for specified by comma-separated values passed
@@ -53,13 +54,13 @@ public class TwitterUsersFunctionProperties {
private final Lookup lookup = new Lookup();
/**
- * relevance-based search interface for querying by topical interest, full name,
+ * Relevance-based search interface for querying by topical interest, full name,
* company name, location, or other criteria.
*/
private final Search search = new Search();
public UserQueryType getType() {
- return type;
+ return this.type;
}
public void setType(UserQueryType type) {
@@ -67,20 +68,20 @@ public class TwitterUsersFunctionProperties {
}
public Lookup getLookup() {
- return lookup;
+ return this.lookup;
}
public Search getSearch() {
- return search;
+ return this.search;
}
@AssertTrue(message = "Per query type validate the required parameters")
public boolean checkParametersPerType() {
- if (this.getType() == UserQueryType.lookup) {
- return (this.getLookup().getScreenName() != null) || (this.getLookup().getUserId() != null);
+ if (getType() == UserQueryType.lookup) {
+ return (getLookup().getScreenName() != null) || (getLookup().getUserId() != null);
}
- else if (this.getType() == UserQueryType.search) {
- return (this.getSearch().getQuery() != null);
+ else if (getType() == UserQueryType.search) {
+ return (getSearch().getQuery() != null);
}
return false;
@@ -102,7 +103,7 @@ public class TwitterUsersFunctionProperties {
private Expression screenName;
public Expression getUserId() {
- return userId;
+ return this.userId;
}
public void setUserId(Expression userId) {
@@ -110,7 +111,7 @@ public class TwitterUsersFunctionProperties {
}
public Expression getScreenName() {
- return screenName;
+ return this.screenName;
}
public void setScreenName(Expression screenName) {
@@ -132,7 +133,7 @@ public class TwitterUsersFunctionProperties {
private int page = 3;
public Expression getQuery() {
- return query;
+ return this.query;
}
public void setQuery(Expression query) {
@@ -140,7 +141,7 @@ public class TwitterUsersFunctionProperties {
}
public int getPage() {
- return page;
+ return this.page;
}
public void setPage(int page) {
diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/package-info.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/package-info.java
new file mode 100644
index 00000000..9c1b358f
--- /dev/null
+++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The Twitter Users function auto-configuration.
+ */
+package org.springframework.cloud.fn.twitter.users;
diff --git a/function/spring-twitter-function/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/function/spring-twitter-function/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 00000000..72bc7b5d
--- /dev/null
+++ b/function/spring-twitter-function/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,3 @@
+org.springframework.cloud.fn.twitter.geo.TwitterGeoFunctionConfiguration
+org.springframework.cloud.fn.twitter.trend.TwitterTrendFunctionConfiguration
+org.springframework.cloud.fn.twitter.users.TwitterUsersFunctionConfiguration
diff --git a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTest.java b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTests.java
similarity index 87%
rename from function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTest.java
rename to function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTests.java
index 2bd6801a..f8111a03 100644
--- a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTest.java
+++ b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,13 +40,11 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.fn.common.twitter.TwitterConnectionProperties;
import org.springframework.cloud.fn.common.twitter.util.TwitterTestUtils;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
-import org.springframework.test.util.TestSocketUtils;
import org.springframework.util.MimeTypeUtils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -58,17 +56,14 @@ import static org.mockserver.verify.VerificationTimes.once;
/**
* @author Christian Tzolov
*/
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE,
- properties = { "twitter.connection.consumerKey=consumerKey666",
- "twitter.connection.consumerSecret=consumerSecret666", "twitter.connection.accessToken=accessToken666",
- "twitter.connection.accessTokenSecret=accessTokenSecret666" })
+@SpringBootTest(properties = { "twitter.connection.consumerKey=consumerKey666",
+ "twitter.connection.consumerSecret=consumerSecret666", "twitter.connection.accessToken=accessToken666",
+ "twitter.connection.accessTokenSecret=accessTokenSecret666" })
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
-public abstract class TwitterGeoFunctionTest {
+public abstract class TwitterGeoFunctionTests {
private static final String MOCK_SERVER_IP = "127.0.0.1";
- private static final Integer MOCK_SERVER_PORT = TestSocketUtils.findAvailableTcpPort();
-
private static ClientAndServer mockServer;
private static MockServerClient mockClient;
@@ -90,8 +85,8 @@ public abstract class TwitterGeoFunctionTest {
@BeforeAll
public static void startMockServer() {
- mockServer = ClientAndServer.startClientAndServer(MOCK_SERVER_PORT);
- mockClient = new MockServerClient(MOCK_SERVER_IP, MOCK_SERVER_PORT);
+ mockServer = ClientAndServer.startClientAndServer();
+ mockClient = new MockServerClient(MOCK_SERVER_IP, mockServer.getPort());
}
@AfterAll
@@ -101,7 +96,7 @@ public abstract class TwitterGeoFunctionTest {
@TestPropertySource(
properties = { "twitter.geo.search.ip='127.0.0.1'", "twitter.geo.search.query=payload.toUpperCase()" })
- public static class TwitterGeoSearchByIPAndQueryTests extends TwitterGeoFunctionTest {
+ public static class TwitterGeoSearchByIPAndQueryTests extends TwitterGeoFunctionTests {
@Test
public void testOne() throws IOException {
@@ -125,7 +120,7 @@ public abstract class TwitterGeoFunctionTest {
assertThat(outPayload).isNotNull();
- List places = new ObjectMapper().readValue(outPayload, List.class);
+ List> places = new ObjectMapper().readValue(outPayload, List.class);
assertThat(places).hasSize(12);
}
@@ -133,7 +128,7 @@ public abstract class TwitterGeoFunctionTest {
@TestPropertySource(properties = { "twitter.geo.location.lat='52.378'", "twitter.geo.location.lon='4.9'",
"twitter.geo.search.query=payload.toUpperCase()" })
- public static class TwitterGeoSearchByLocationTests extends TwitterGeoFunctionTest {
+ public static class TwitterGeoSearchByLocationTests extends TwitterGeoFunctionTests {
@Test
public void testOne() throws IOException {
@@ -159,7 +154,7 @@ public abstract class TwitterGeoFunctionTest {
assertThat(outPayload).isNotNull();
- List places = new ObjectMapper().readValue(outPayload, List.class);
+ List> places = new ObjectMapper().readValue(outPayload, List.class);
assertThat(places).hasSize(12);
}
@@ -167,7 +162,7 @@ public abstract class TwitterGeoFunctionTest {
@TestPropertySource(properties = { "twitter.geo.type=reverse", "twitter.geo.location.lat='52.378'",
"twitter.geo.location.lon='4.9'" })
- public static class TwitterGeoSearchByLocation2Tests extends TwitterGeoFunctionTest {
+ public static class TwitterGeoSearchByLocation2Tests extends TwitterGeoFunctionTests {
@Test
public void testOne() throws IOException {
@@ -191,7 +186,7 @@ public abstract class TwitterGeoFunctionTest {
assertThat(outPayload).isNotNull();
- List places = new ObjectMapper().readValue(outPayload, List.class);
+ List> places = new ObjectMapper().readValue(outPayload, List.class);
assertThat(places).hasSize(12);
}
@@ -200,7 +195,7 @@ public abstract class TwitterGeoFunctionTest {
@TestPropertySource(properties = { "twitter.geo.location.lat=#jsonPath(new String(payload),'$.location.lat')",
"twitter.geo.location.lon=#jsonPath(new String(payload),'$.location.lon')",
"twitter.geo.search.query=#jsonPath(new String(payload),'$.country')" })
- public static class TwitterGeoSearchJsonPathTests extends TwitterGeoFunctionTest {
+ public static class TwitterGeoSearchJsonPathTests extends TwitterGeoFunctionTests {
@Test
public void testOne() throws IOException {
@@ -228,7 +223,7 @@ public abstract class TwitterGeoFunctionTest {
assertThat(outPayload).isNotNull();
- List places = new ObjectMapper().readValue(outPayload, List.class);
+ List> places = new ObjectMapper().readValue(outPayload, List.class);
assertThat(places).hasSize(12);
}
@@ -236,7 +231,6 @@ public abstract class TwitterGeoFunctionTest {
@SpringBootConfiguration
@EnableAutoConfiguration
- @Import(TwitterGeoFunctionConfiguration.class)
public static class TwitterGeoFunctionTestApplication {
@Bean
@@ -246,7 +240,7 @@ public abstract class TwitterGeoFunctionTest {
Function mockedConfiguration = toConfigurationBuilder
.andThen(new TwitterTestUtils()
- .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT)));
+ .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, mockServer.getPort())));
return mockedConfiguration.apply(properties).build();
}
diff --git a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionTests.java b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionTests.java
index 08f2e228..1fa07062 100644
--- a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionTests.java
+++ b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,13 +35,11 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.fn.common.twitter.TwitterConnectionProperties;
import org.springframework.cloud.fn.common.twitter.util.TwitterTestUtils;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
-import org.springframework.test.util.TestSocketUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockserver.matchers.Times.exactly;
@@ -61,8 +59,6 @@ public abstract class TwitterTrendFunctionTests {
private static final String MOCK_SERVER_IP = "127.0.0.1";
- private static final Integer MOCK_SERVER_PORT = TestSocketUtils.findAvailableTcpPort();
-
private static ClientAndServer mockServer;
private static MockServerClient mockClient;
@@ -74,8 +70,8 @@ public abstract class TwitterTrendFunctionTests {
@BeforeAll
public static void startServer() {
- mockServer = ClientAndServer.startClientAndServer(MOCK_SERVER_PORT);
- mockClient = new MockServerClient(MOCK_SERVER_IP, MOCK_SERVER_PORT);
+ mockServer = ClientAndServer.startClientAndServer();
+ mockClient = new MockServerClient(MOCK_SERVER_IP, mockServer.getPort());
trendsRequest = setExpectation(
request().withMethod("GET").withPath("/trends/place.json").withQueryStringParameter("id", "2972"));
@@ -96,7 +92,8 @@ public abstract class TwitterTrendFunctionTests {
return request;
}
- @TestPropertySource(properties = { "twitter.trend.locationId='2972'", "twitter.connection.rawJson=true" })
+ @TestPropertySource(properties = { "twitter.trend.trendQueryType=trend", "twitter.trend.locationId='2972'",
+ "twitter.connection.rawJson=true" })
public static class TwitterTrendPayloadTests extends TwitterTrendFunctionTests {
@Test
@@ -110,7 +107,6 @@ public abstract class TwitterTrendFunctionTests {
@SpringBootConfiguration
@EnableAutoConfiguration
- @Import(TwitterTrendFunctionConfiguration.class)
public static class TwitterTrendFunctionTestApplication {
@Bean
@@ -120,7 +116,7 @@ public abstract class TwitterTrendFunctionTests {
Function mockedConfiguration = toConfigurationBuilder
.andThen(new TwitterTestUtils()
- .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT)));
+ .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, mockServer.getPort())));
return mockedConfiguration.apply(properties).build();
}
diff --git a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionTests.java b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionTests.java
index fa334fbb..4a20981e 100644
--- a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionTests.java
+++ b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,13 +38,11 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.fn.common.twitter.TwitterConnectionProperties;
import org.springframework.cloud.fn.common.twitter.util.TwitterTestUtils;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
-import org.springframework.test.util.TestSocketUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockserver.matchers.Times.exactly;
@@ -64,8 +62,6 @@ public abstract class TwitterUsersFunctionTests {
private static final String MOCK_SERVER_IP = "127.0.0.1";
- private static final Integer MOCK_SERVER_PORT = TestSocketUtils.findAvailableTcpPort();
-
private static ClientAndServer mockServer;
private static MockServerClient mockClient;
@@ -94,8 +90,8 @@ public abstract class TwitterUsersFunctionTests {
@BeforeAll
public static void startServer() {
- mockServer = ClientAndServer.startClientAndServer(MOCK_SERVER_PORT);
- mockClient = new MockServerClient(MOCK_SERVER_IP, MOCK_SERVER_PORT);
+ mockServer = ClientAndServer.startClientAndServer();
+ mockClient = new MockServerClient(MOCK_SERVER_IP, mockServer.getPort());
searchUsersRequest = setExpectation(request().withMethod("GET")
.withPath("/users/search.json")
@@ -127,7 +123,7 @@ public abstract class TwitterUsersFunctionTests {
Message> received = twitterUsersFunction.apply(MessageBuilder.withPayload("tzolov").build());
mockClient.verify(searchUsersRequest, once());
assertThat(received).isNotNull();
- List list = mapper.readValue(new String((byte[]) received.getPayload()), List.class);
+ List> list = mapper.readValue(new String((byte[]) received.getPayload()), List.class);
assertThat(list).hasSize(20);
}
@@ -144,7 +140,7 @@ public abstract class TwitterUsersFunctionTests {
mockClient.verify(lookupUsersRequest, once());
assertThat(received).isNotNull();
- List list = mapper.readValue(new String((byte[]) received.getPayload()), List.class);
+ List> list = mapper.readValue(new String((byte[]) received.getPayload()), List.class);
assertThat(list).hasSize(5);
}
@@ -164,7 +160,7 @@ public abstract class TwitterUsersFunctionTests {
mockClient.verify(lookupUsersRequest2, once());
assertThat(received).isNotNull();
- List list = mapper.readValue(new String((byte[]) received.getPayload()), List.class);
+ List> list = mapper.readValue(new String((byte[]) received.getPayload()), List.class);
assertThat(list).hasSize(5);
}
@@ -172,17 +168,16 @@ public abstract class TwitterUsersFunctionTests {
@SpringBootConfiguration
@EnableAutoConfiguration
- @Import(TwitterUsersFunctionConfiguration.class)
static class TwitterUsersFunctionTestApplication {
@Bean
@Primary
- public twitter4j.conf.Configuration twitterConfiguration2(TwitterConnectionProperties properties,
+ twitter4j.conf.Configuration twitterConfiguration2(TwitterConnectionProperties properties,
Function toConfigurationBuilder) {
Function mockedConfiguration = toConfigurationBuilder
.andThen(new TwitterTestUtils()
- .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT)));
+ .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, mockServer.getPort())));
return mockedConfiguration.apply(properties).build();
}