opencsv 5.1
Caused by: com.opencsv.exceptions.CsvRequiredFieldEmptyException: Header is missing required fields [ALGVERIFICATION, DISTAL MV, LOCATION, PREDICTED STATE, PROXIMAL MV, RUN, SAMPLE TIME]. The list of headers encountered is [].
at com.opencsv.bean.HeaderNameBaseMappingStrategy.captureHeader(HeaderNameBaseMappingStrategy.java:69)
#ParameterizedTest
#ArgumentsSource(MyArgumentsProvider.class)
void test( AlgorithmVerification verifications )
{
Log.d("test", verifications.location);
assertThat(verifications).isNotNull();
}
public enum State {
NA,
ADVANCE,
RETRACT,
}
public static class StateConverter extends AbstractBeanField {
#Override
protected Object convert(String value) {
return State.valueOf(value);
}
}
public static class AlgorithmVerification {
#CsvBindByName(column = "Sample Time", required = true)
protected float sampleTime;
#CsvBindByName(column = "Distal mV", required = true)
protected int distalMV;
#CsvBindByName(column = "Proximal mV", required = true)
protected int proximalMV;
#CsvCustomBindByName(column = "Predicted State", converter = StateConverter.class, required = true)
protected State predictedState;
#CsvBindByName(column = "run", required = true)
protected String run;
#CsvCustomBindByName(column = "Location", converter = StateConverter.class, required = true)
protected String location;
#CsvCustomBindByName(column = "AlgVerification", converter = StateConverter.class, required = true)
protected State algVerification;
}
static class MyArgumentsProvider implements ArgumentsProvider {
#Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws IOException, URISyntaxException {
return Files.list(Paths.get(ClassLoader.getSystemResource("avd").toURI()))
.map(Path::toFile)
.map( f -> Try.withResources( () -> new FileReader(f) )
.of(CsvToBeanBuilder::new)
.map(b -> b.withType(AlgorithmVerification.class) )
.map(CsvToBeanBuilder::build)
.map(CsvToBean::parse)
.getOrElseThrow((throwable) -> new RuntimeException(f.getName(), throwable))
)
.flatMap(List::stream)
.map(Arguments::of);
}
}
and this is the beginning of the file
Sample Time,Distal mV,Proximal mV,Predicted State,run,Location,AlgVerification
0.016,2509,2502,NA,DV-MyString,-1,-1
Did I miss a step? are the headers wrong somehow? I notice that it's looking for uppercase headers... but even then it's finding none
looks like my usage of vavr Try.withResources is wrong, it needed to be this
return Files.list(Paths.get(ClassLoader.getSystemResource("avd").toURI()))
.map(Path::toFile)
.map( f -> Try.withResources( () -> new FileReader(f) )
.of((fr ) -> new CsvToBeanBuilder<AlgorithmVerification>(fr)
.withType(AlgorithmVerification.class)
.build()
.parse())
.getOrElseThrow((throwable) -> new RuntimeException(f.getName(), throwable))
)
.flatMap(List::stream)
.map(Arguments::of);
Related
I want to extract string from API response and assign that to a object. When print that value it will display but couldn't assign to a object. Please check below sample code base.
List<DtvPrePacksDataResponse> dtvPrePacksDataResponses =
channelGroupByGenre.entrySet().stream()
.map(e -> {
DtvPrePacksDataResponse dtvPrePacksDataResponse = new DtvPrePacksDataResponse();
dtvPrePacksDataResponse.setCatId(counter.incrementAndGet());
dtvPrePacksDataResponse.setCategoryName(e.getKey());
dtvPrePacksDataResponse.setChannelCount(e.getValue().size());
String channelCat = e.getValue().get(0).getProductCategoryId();
String channelSubcat = e.getValue().get(0).getProductSubCategoryId();
this.getChannelCatIcon(channelCat, channelSubcat)
.subscribe(
s -> this.catIconSet(dtvPrePacksDataResponse, s)
//s -> dtvPrePacksDataResponse.setCategoryIcon(s)
/*value -> System.out.println(value),
error -> error.printStackTrace(),
() -> System.out.println("completed without a value")*/
);
return dtvPrePacksDataResponse;
}).collect(Collectors.toList());
Retrive image from API response
private Mono<String> getChannelCatIcon(String channelCat, String channelSubcat) {
return productSubcategoryQueryClientInterface.getProductSubcategoryInfo(
channelCat,
channelSubcat
)
.collectList()
.map(productSubcategories -> {
ProductSubcategory productSubcategory = productSubcategories.stream()
.filter(productSubcategory1 -> productSubcategory1.getProductCategoryId().equals(channelCat) && productSubcategory1.getProductSubCategoryId().equals(channelSubcat))
.findFirst()
.orElseThrow(() -> new RuntimeException(INVALID_LANGUAGE_OBJECT));
ListSubcategoryUrl listSubcategoryUrl = productSubcategory.getListSubcategoryUrl().stream()
.filter(listSubcategoryUrl1 -> listSubcategoryUrl1.getProductUrlCode().equals("SUBCATEGORY_IMAGE") && listSubcategoryUrl1.getType().equals("IMAGE"))
.findFirst()
.orElseThrow(() -> new RuntimeException(INVALID_LANGUAGE_OBJECT));
return listSubcategoryUrl.getUrl();
}).cache();
}
Set Image to the object
private void catIconSet(DtvPrePacksDataResponse dtvPrePacksDataResponse, String url){
System.out.println("img url " + url);
dtvPrePacksDataResponse.setCategoryIcon(url);
}
Entity class
public class DtvPrePacksDataResponse {
private int catId;
private String categoryName;
private String categoryIcon;
private int channelCount;
private List<DtvPrePacksDataListResponse> channelList;
}
Using block() gives a error. Tried using flatmap() also gives error. Checked below question also and tried but no success
How to get String from Mono<String> in reactive java
How to extract string from Mono<String> in reactor core
I am using JPA to store data and faced two problems during implementation. I have two entities (Station and Commodity) that have many-to-many relationship with intermediate table so that I had to created the third one. When app receives message it converts its data to entites and should save but sometimes app throwing a ConstraintViolationException because there is null value at foreign key field referencing to Commodity entity.
I've tried simple approach: selecting needed commodity from database and saving it if there is no one. Then I started to use bulk searching all commodities of message and then putting it where are needed. None of them did a trick.
In my opinion the problem could be caused by multi-threading read\insert.
The second problem is that service stop running when exception is thrown. App can lost some of transactions that's not a big deal but it simply stops after rollback.
How can I resolve these conflicts?
Here is code of data handling class and diagram of entities :
#Service
#AllArgsConstructor
#Slf4j
public class ZeromqCommoditiesServiceImpl implements ZeromqCommoditesService {
private final CategoryTransactionHandler categoryHandler;
private final CommodityTransactionHandler commodityHandler;
private final EconomyTransactionHandler economyHandler;
private final StationTransactionHandler stationHandler;
private final SystemTransactionHandler systemHandler;
#Override
#Transactional(
isolation = Isolation.READ_COMMITTED,
propagation = Propagation.REQUIRES_NEW,
rollbackFor = Throwable.class)
#Modifying
public void saveData(ZeromqCommodityPayload payload) {
CommodityContent content = payload.getContent();
var station = stationHandler.createOrFindStation(content.getStationName());
var system = systemHandler.createOrFindSystem(content.getSystemName());
var commodityReferences = getMapOfCommodities(content);
station.setSystem(system);
updateEconomies(station, content);
updateProhibited(station, content, commodityReferences);
updateStationCommodities(station, content, commodityReferences);
try {
saveStation(station);
} catch (ConstraintViolationException | PersistentObjectException | DataAccessException e) {
log.error("Error saving commodity info \n" + content, e);
}
}
public void saveStation(StationEntity station) {
stationHandler.saveStation(station);
if (station.getId() != null) {
log.debug(String.format("Updated \"%s\" station info", station.getName()));
} else {
log.debug(String.format("Updated \"%s\" station info", station.getName()));
}
}
private void updateEconomies(StationEntity station, CommodityContent content) {
station.getEconomies().clear();
if (content.getEconomies() != null) {
var economies = content.getEconomies()
.stream()
.map(economy -> {
var stationEconomyEntity = economyHandler.createOrFindEconomy(economy.getName());
Double proportion = economy.getProportion();
stationEconomyEntity.setProportion(proportion != null ? proportion : 1.0);
return stationEconomyEntity;
})
.peek(economy -> economy.setStation(station))
.toList();
station.getEconomies().addAll(economies);
}
}
private void updateProhibited(
StationEntity station,
CommodityContent content,
Map<String, CommodityEntity> commodityEntityMap) {
station.getProhibited().clear();
if (content.getProhibited() != null) {
var prohibitedCommodityEntities = content.getProhibited()
.stream()
.map(prohibited -> {
String eddnName = prohibited.toLowerCase(Locale.ROOT);
CommodityEntity commodityReference = getCommodityEntity(commodityEntityMap, eddnName);
return new ProhibitedCommodityEntity(station, commodityReference);
}
)
.toList();
station.getProhibited().addAll(prohibitedCommodityEntities);
}
}
private void updateStationCommodities(
StationEntity station,
CommodityContent content,
Map<String, CommodityEntity> commodityEntityMap) {
station.getCommodities().clear();
if (content.getCommodities() != null) {
var commodities = content.getCommodities()
.stream()
.map(commodity -> {
CommodityEntity commodityReference = getCommodityEntity(
commodityEntityMap,
commodity.getEddnName());
return StationCommodityEntity.builder()
.commodity(commodityReference)
.buyPrice(commodity.getBuyPrice())
.sellPrice(commodity.getSellPrice())
.demand(commodity.getDemand())
.stock(commodity.getStock())
.station(station)
.build();
})
.toList();
station.getCommodities().addAll(commodities);
}
}
private CommodityEntity getCommodityEntity(Map<String, CommodityEntity> commodityEntityMap, String eddnName) {
return commodityEntityMap.get(eddnName);
}
private Map<String, CommodityEntity> getMapOfCommodities(#NotNull CommodityContent content) {
Set<String> commodities = content.getCommodities()
.stream()
.map(Commodity::getEddnName)
.collect(Collectors.toSet());
if (content.getProhibited() != null && content.getProhibited().size() > 0) {
commodities.addAll(content.getProhibited().
stream()
.map(item -> item.toLowerCase(Locale.ROOT))
.collect(Collectors.toSet()));
}
var commodityReferencesMap = commodityHandler.findAllByEddnName(commodities)
.stream()
.collect(Collectors.toMap(
CommodityEntity::getEddnName,
item -> item
));
commodities.forEach(commodity -> {
if (commodityReferencesMap.get(commodity.toLowerCase()) == null) {
CommodityCategoryEntity category = categoryHandler.createOrFindCategory("Unknown");
CommodityEntity newCommodity = new CommodityEntity(commodity, commodity, category);
CommodityEntity managedCommodity = commodityHandler.saveCommodity(newCommodity);
commodityReferencesMap.put(managedCommodity.getEddnName(), managedCommodity);
}
});
return commodityReferencesMap;
}
}
Thanks in advance
I have defined a global RequestSpecification with some pathParams and using the spec in all requests. But not all the params used in the global spec would be used in requests.
Assume I have mentioned 3 in the globalSpec and in some requests I would only be needing 2 params and in some 1 and in some 0 params.
But Rest-Assured is throwing NoParameterValue exception
Invalid number of path parameters. Expected 1, was 2. Redundant path parameters are: customerOrderId=io.restassured.internal.NoParameterValue#753b84c6.
java.lang.IllegalArgumentException: Invalid number of path parameters. Expected 1, was 2. Redundant path parameters are
Is there any inbuilt config/ignore mechanism that I can use to make rest-assured not throw exceptions?
Sample Code
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import static io.restassured.RestAssured.given;
public class TestRestAssuredParams {
private RequestSpecification defaultRequestSpec = new RequestSpecBuilder()
.addPathParams(
"env", "value1",
"customer", "value2",
"order", "value3"
)
.setContentType(ContentType.JSON)
.build();
private void reqWithNoParam() {
given()
.spec(defaultRequestSpec)
.get("https://www.testapi.com/dev");
}
private void reqWith1Param() {
given()
.spec(defaultRequestSpec)
.get("https://www.testapi.com/{env}");
}
private void reqWith2Param() {
given()
.spec(defaultRequestSpec)
.get("https://www.testapi.com/{env}/{customer}");
}
private void reqWith3Param() {
given()
.spec(defaultRequestSpec)
.get("https://www.testapi.com/{env}/{customer}/order/{order}");
}
public static void main(String[] args) {
TestRestAssuredParams testRestAssuredParams = new TestRestAssuredParams();
testRestAssuredParams.reqWithNoParam();
testRestAssuredParams.reqWith1Param();
testRestAssuredParams.reqWith2Param();
testRestAssuredParams.reqWith3Param();
}
}
How to make sure RestAssured handle the above scenario.
RestAssured version - 4.3.0
Java - 11.0.5
You will have to use the removeParam of FilterableRequestSpecification,
private void reqWithNoParam() {
given().filter((requestSpec, responseSpec, ctx) -> {
requestSpec.removePathParam("env");
requestSpec.removePathParam("customer");
requestSpec.removePathParam("order");
return ctx.next(requestSpec, responseSpec);
}).spec(defaultRequestSpec).log().all().get("https://www.testapi.com/dev");
}
private void reqWith1Param() {
given().filter((requestSpec, responseSpec, ctx) -> {
requestSpec.removePathParam("customer");
requestSpec.removePathParam("order");
return ctx.next(requestSpec, responseSpec);
}).spec(defaultRequestSpec).log().all().get("https://www.testapi.com/{env}");
}
private void reqWith2Param() {
given().filter((requestSpec, responseSpec, ctx) -> {
requestSpec.removePathParam("order");
return ctx.next(requestSpec, responseSpec);
}).spec(defaultRequestSpec).log().all().get("https://www.testapi.com/{env}/{customer}");
}
private void reqWith3Param() {
given().spec(defaultRequestSpec).log().all().get("https://www.testapi.com/{env}/{customer}/order/{order}");
}
removePathParam in the filter does the trick.
FilterableRequestSpecification has a methond getPathParamPlaceholders which will give the params from the url mapped in the request. I removed the unneeded pathParams using that.
private RequestSpecification defaultRequestSpec = new RequestSpecBuilder()
.addPathParams(
"env", "value1",
"customer", "value2",
"order", "value3"
)
.addFilter((requestSpec, responseSpec, ctx) -> {
var paramsFromRequest = requestSpec.getPathParamPlaceholders();
var finalRequestSpec = requestSpec;
finalRequestSpec
.getPathParams()
.forEach((key, val) -> {
if (!paramsFromRequest.contains(key)) {
finalRequestSpec.removePathParam(key);
}
});
return ctx.next(finalRequestSpec, responseSpec);
})
.setContentType(ContentType.JSON)
.build();
I've been tinkering with wrapping an old style listener interface using RxJava. What i've come up with seems to work, but the usage of Observable.using feels a bit awkward.
The requirements are:
Only one subscription per id to the underlying service.
The latest value for a given id should be cached and served to new subscribers.
We must unsubscribe from the underlying service if nothing is listening to an id.
Is there a better way? The following is what I've got.
static class MockServiceRXAdapterImpl1 implements MockServiceRXAdapter {
PublishSubject<MockResponse> mockResponseObservable = PublishSubject.create();
MockService mockService = new MockService(mockResponse -> mockResponseObservable.onNext(mockResponse));
final ConcurrentMap<String, Observable<String>> subscriptionMap = new ConcurrentHashMap<>();
public Observable<String> getObservable(String id) {
return Observable.using(() -> subscriptionMap.computeIfAbsent(
id,
key -> mockResponseObservable.filter(mockResponse -> mockResponse.id.equals(id))
.doOnSubscribe(disposable -> mockService.subscribe(id))
.doOnDispose(() -> {
mockService.unsubscribe(id);
subscriptionMap.remove(id);
})
.map(mockResponse -> mockResponse.value)
.replay(1)
.refCount()),
observable -> observable,
observable -> {
}
);
}
}
You may use Observable.create
So code may look like this
final Map<String, Observable<String>> subscriptionMap = new HashMap<>();
MockService mockService = new MockService();
public Observable<String> getObservable(String id) {
log.info("looking for root observable");
if (subscriptionMap.containsKey(id)) {
log.info("found root observable");
return subscriptionMap.get(id);
} else {
synchronized (subscriptionMap) {
if (!subscriptionMap.containsKey(id)) {
log.info("creating new root observable");
final Observable<String> responseObservable = Observable.create(emitter -> {
MockServiceListener listener = emitter::onNext;
mockService.addListener(listener);
emitter.setCancellable(() -> {
mockServices.removeListener(listener);
mockService.unsubscribe(id);
synchronized (subscriptionMap) {
subscriptionMap.remove(id);
}
});
mockService.subscribe(id);
})
.filter(mockResponse -> mockResponse.id.equals(id))
.map(mockResponse -> mockResponse.value)
.replay(1)
.refCount();
subscriptionMap.put(id, responseObservable);
} else {
log.info("Another thread created the observable for us");
}
return subscriptionMap.get(id);
}
}
}
I think I've gotten it to work using .groupBy(...).
In my case Response.getValue() returns an int, but you get the idea:
class Adapter
{
Subject<Response> msgSubject;
ThirdPartyService service;
Map<String, Observable<Integer>> observables;
Observable<GroupedObservable<String, Response>> groupedObservables;
public Adapter()
{
msgSubject = PublishSubject.<Response>create().toSerialized();
service = new MockThirdPartyService( msgSubject::onNext );
groupedObservables = msgSubject.groupBy( Response::getId );
observables = Collections.synchronizedMap( new HashMap<>() );
}
public Observable<Integer> getObservable( String id )
{
return observables.computeIfAbsent( id, this::doCreateObservable );
}
private Observable<Integer> doCreateObservable( String id )
{
service.subscribe( id );
return groupedObservables
.filter( group -> group.getKey().equals( id ))
.doOnDispose( () -> {
synchronized ( observables )
{
service.unsubscribe( id );
observables.remove( id );
}
} )
.concatMap( Functions.identity() )
.map( Response::getValue )
.replay( 1 )
.refCount();
}
}
In my controller, I receive a string parameter on the basis of which I need to decide which service to call, how can I do the same in my Spring Boot application using Spring annotations?
For example: we have different types of cars. Now, on the basis of parameter in the request I should be able to decide which particular car service I should call.
How can I have a factory using annotations in Spring Boot, and objects should be returned from that factory on the basis of input.
I remember implementing support for this approach a few years ago, I believe inspired and using https://www.captechconsulting.com/blogs/combining-strategy-pattern-and-spring as the entry point to my utility library, use the following code snippets at your convenience:
Strategy.java
package ...
#Documented
#Target({ ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
public #interface Strategy {
Class<?> type();
String[] profiles() default {};
}
StrategyFactory.java
package ...
public class StrategyFactory {
private static final Logger LOG = Logger.getLogger( StrategyFactory.class );
private Map<Class<?>, Strategy> strategiesCache = new HashMap<Class<?>, Strategy>();
private String[] packages;
#PostConstruct
public void init() {
if (this.packages != null) {
Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
for (String pack : this.packages) {
Reflections reflections = new Reflections( pack );
annotatedClasses.addAll( reflections.getTypesAnnotatedWith( Strategy.class ) );
}
this.sanityCheck( annotatedClasses );
}
}
public <T> T getStrategy(Class<T> strategyClass) {
return this.getStrategy( strategyClass, null );
}
#SuppressWarnings("unchecked")
public <T> T getStrategy(Class<T> strategyClass, String currentProfile) {
Class<T> clazz = (Class<T>) this.findStrategyMatchingProfile( strategyClass, currentProfile );
if (clazz == null) {
throw new StrategyNotFoundException( String.format( "No strategies found of type '%s', are the strategies marked with #Strategy?", strategyClass.getName() ) );
}
try {
return (T) clazz.newInstance();
} catch (Exception e) {
throw ExceptionUtils.rethrowAs( e, StrategyException.class );
}
}
/**
* Checks to make sure there is only one strategy of each type(Interface) annotated for each profile Will throw an exception on startup if multiple strategies are mapped to the same profile.
* #param annotatedClasses a list of classes
*/
private void sanityCheck(Set<Class<?>> annotatedClasses) {
Set<String> usedStrategies = new HashSet<String>();
for (Class<?> annotatedClass : annotatedClasses) {
Strategy strategyAnnotation = AnnotationUtils.findAnnotation( annotatedClass, Strategy.class );
if (!strategyAnnotation.type().isAssignableFrom( annotatedClass )) {
throw new StrategyProfileViolationException( String.format( "'%s' should be assignable from '%s'", strategyAnnotation.type(), annotatedClass ) );
}
this.strategiesCache.put( annotatedClass, strategyAnnotation );
if (this.isDefault( strategyAnnotation )) {
this.ifNotExistAdd( strategyAnnotation.type(), "default", usedStrategies );
} else {
for (String profile : strategyAnnotation.profiles()) {
this.ifNotExistAdd( strategyAnnotation.type(), profile, usedStrategies );
}
}
}
}
private void ifNotExistAdd(Class<?> type, String profile, Set<String> usedStrategies) {
String key = this.createKey( type, profile );
if (usedStrategies.contains( key )) {
throw new StrategyProfileViolationException( String.format( "There can only be a single strategy for each type, found multiple for type '%s' and profile '%s'", type, profile ) );
}
usedStrategies.add( key );
}
private String createKey(Class<?> type, String profile) {
return String.format( "%s_%s", type, profile ).toLowerCase();
}
private boolean isDefault(Strategy strategyAnnotation) {
return (strategyAnnotation.profiles().length == 0);
}
private Class<?> findStrategyMatchingProfile(Class<?> strategyClass, String currentProfile) {
for (Map.Entry<Class<?>, Strategy> strategyCacheEntry : this.strategiesCache.entrySet()) {
Strategy strategyCacheEntryValue = strategyCacheEntry.getValue();
if (strategyCacheEntryValue.type().equals( strategyClass )) {
if (currentProfile != null) {
for (String profile : strategyCacheEntryValue.profiles()) {
if (currentProfile.equals( profile )) {
Class<?> result = strategyCacheEntry.getKey();
if (LOG.isDebugEnabled()) {
LOG.debug( String.format( "Found strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, result ) );
}
return result;
}
}
} else if (this.isDefault( strategyCacheEntryValue )) {
Class<?> defaultClass = strategyCacheEntry.getKey();
if (LOG.isDebugEnabled()) {
LOG.debug( String.format( "Found default strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, defaultClass ) );
}
return defaultClass;
}
}
}
return null;
}
public void setPackages(String[] packages) {
this.packages = packages;
}
}
StrategyException.java
package ...
public class StrategyException extends RuntimeException {
...
}
StrategyNotFoundException.java
package ...
public class StrategyNotFoundException extends StrategyException {
...
}
StrategyProfileViolationException.java
package ...
public class StrategyProfileViolationException extends StrategyException {
...
}
Usage without Spring:
NavigationStrategy.java
package com.asimio.core.test.strategy.strategies.navigation;
public interface NavigationStrategy {
public String naviateTo();
}
FreeNavigationStrategy.java
package com.asimio.core.test.strategy.strategies.navigation;
#Strategy(type = NavigationStrategy.class)
public class FreeNavigationStrategy implements NavigationStrategy {
public String naviateTo() {
return "free";
}
}
LimitedPremiumNavigationStrategy.java
package com.asimio.core.test.strategy.strategies.navigation;
#Strategy(type = NavigationStrategy.class, profiles = { "limited", "premium" })
public class LimitedPremiumNavigationStrategy implements NavigationStrategy {
public String naviateTo() {
return "limited+premium";
}
}
Then
...
StrategyFactory factory = new StrategyFactory();
factory.setPackages( new String[] { "com.asimio.core.test.strategy.strategies.navigation" } );
this.factory.init();
NavigationStrategy ns = this.factory.getStrategy( NavigationStrategy.class );
String result = ns.naviateTo();
Assert.assertThat( "free", Matchers.is( result ) );
...
Or
...
String result = factory.getStrategy( NavigationStrategy.class, "limited" ).naviateTo();
Assert.assertThat( "limited+premium", Matchers.is( result ) );
...
Usage with Spring:
Spring context file:
<bean id="strategyFactory" class="com.asimio.core.strategy.StrategyFactory">
<property name="packages">
<list>
<value>com.asimio.jobs.feed.impl</value>
</list>
</property>
</bean>
IFeedProcessor.java
package ...
public interface IFeedProcessor {
void runBatch(String file);
}
CsvRentalsFeedProcessor.java
package ...
#Configurable(dependencyCheck = true)
#Strategy(type = IFeedProcessor.class, profiles = { "csv" })
public class CsvRentalsFeedProcessor implements IFeedProcessor, Serializable {
#Autowired
private CsvRentalsBatchReporter batchReporter;
...
}
Then
...
IFeedProcessor feedProcessor = this.strategyFactory.getStrategy( IFeedProcessor.class, feedFileExt );
feedProcessor.runBatch( unzippedFeedDir.getAbsolutePath() + File.separatorChar + feedFileName );
...
Notice CsvRentalsBatchReporter is "injected" in CsvRentalsFeedProcessor bean (a Strategy implementation) but StrategyFactory instantiates the strategy implementation using return (T) clazz.newInstance();, so what's needed to make this object Spring-aware?
First CsvRentalsFeedProcessor to be annotated with #Configurable(dependencyCheck = true) and when running the Java application this argument is needed in the java command: -javaagent:<path to spring-agent-${spring.version}.jar>