Spring Batch XML - Kotlin - Message: Content is not allowed in prolog. kotlin - spring

I`m trying to run a simple spring batch job that read xml in kotlin but i got the error :
...
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[3,1]
Message: Content is not allowed in prolog.
XML Prolog is OK
const val test = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root><test>test</test></root>"
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "test")
class Test(
#XmlValue
var test: String = ""
)
#Configuration
#EnableBatchProcessing
class BatchStgCarbPdv(
#Autowired
val jobBuilderFactory: JobBuilderFactory,
#Autowired
val stepBuilderFactory: StepBuilderFactory
) {
I can't find the error in the reader
fun read(): StaxEventItemReader<Test> {
val reader: StaxEventItemReader<Test> = StaxEventItemReader()
println(StandardCharsets.UTF_8.name())
reader.setEncoding(StandardCharsets.UTF_8.name())
reader.setResource(ByteArrayResource(test.encodeToByteArray()))
val unmarshaller = Jaxb2Marshaller()
unmarshaller.setClassesToBeBound(Test::class.java)
reader.setUnmarshaller(unmarshaller)
reader.setFragmentRootElementName("root")
reader.afterPropertiesSet()
return reader
}
Spring batch...
fun processor(): com.gs.ItemProcessor {
return ItemProcessor()
}
fun writer(): ConsoleItemWriter {
return ConsoleItemWriter()
}
#Bean
fun step1(): Step {
return stepBuilderFactory["step1"]
.chunk<Test, Test>(1)
.reader(read())
.processor(processor())
.writer(writer())
.taskExecutor(SimpleAsyncTaskExecutor("spring_batch"))
.build()
}
#Bean
fun importUserJob(step1: Step): Job {
return jobBuilderFactory["importJob"]
.incrementer(RunIdIncrementer())
.flow(step1)
.end()
.build()
}
}
Do nothing
class ItemProcessor : ItemProcessor<Test, Test> {
override fun process(t: Test): Test {
return t
}
}
class ConsoleItemWriter : ItemWriter<Test?> {
override fun write(items: List<Test?>) {
for (test in items) {
println(test)
}
}
}

Related

Can MockProducer and MockConsumer be used with kafkaTemplate producer

I have a service which using kafkaTemplate to send the kafka message.
#Service
class KafkaProducer(#Autowired val kafkaTemplate: KafkaTemplate<String, String>) {
final fun sendMessage(msg: String) {
val abc = kafkaTemplate.send(AppConstants.TOPIC_NAME, "abc", msg)
abc.whenComplete {
result, ex ->
if (ex != null) {
print("ex occured")
print(ex.message)
} else {
print("sent successfully")
print(result.producerRecord.value())
}
}
}
}
For unit test, I am trying to mock this KafkaProducer.
Can i use MockProducer (import org.apache.kafka.clients.producer.MockProducer) for this?
#Test
fun verify_test() {
val mockProducer = MockProducer(true,StringSerializer(), StringSerializer())
val kafkaProducer = KafkaProducer(mockProducer)
}
On trying the above code, i am getting error bcoz KafkaProducer takes argument as KafkaTemplate object, and I am providing MockProducer.
Here is an example using a mock ProducerFactory...
#SpringJUnitConfig
class So74993413ApplicationTests {
#Test
void test(#Autowired KafkaTemplate<String, String> template,
#Autowired MockProducer<String, String> producer) throws Exception {
CompletableFuture<SendResult<String, String>> future = template.send("foo", "bar");
SendResult<String, String> sendResult = future.get();
// System.out.println(sendResult);
List<ProducerRecord<String, String>> history = producer.history();
assertThat(history).hasSize(1);
ProducerRecord<String, String> record = history.get(0);
assertThat(record.topic()).isEqualTo("foo");
assertThat(record.value()).isEqualTo("bar");
}
#Configuration
public static class Config {
#Bean
MockProducer<String, String> producer() {
return new MockProducer<>(true, new StringSerializer(), new StringSerializer());
}
#Bean
ProducerFactory<String, String> pf (MockProducer producer) {
return new ProducerFactory<>() {
#Override
public Producer<String, String> createProducer() {
return producer;
}
};
}
#Bean
KafkaTemplate<String, String> template(ProducerFactory<String, String> pf) {
return new KafkaTemplate<>(pf);
}
}
}
KafkaTemplate is not a type of Producer. Native Kafka classes cannot be used in place of Spring's - that'd be a reverse dependency.
You would have to mock the template instead since that's what you're actually using. By doing so, it'll bypass any KafkaProducer instance the template used, mock or not.

How do I implement an event listener when the key expires in Spring-Data-Reactive-Redis?

Spring data redis may be implemented as follows.
#Component
class ExpirationListener : MessageListener {
override fun onMessage(message: Message, pattern: ByteArray) {
println("########## onMessage pattern " + String(pattern) + " | " + message.toString())
}
}
#Configuration
class RedisConfig(private val env: Environment) {
#Bean
fun redisConnectionFactory(): RedisConnectionFactory {
val redisHost = env.getProperty("CONF_TRANSACTION_GATEWAY_REDIS_DB_HOST", "localhost")
val redisPort = env.getProperty("CONF_TRANSACTION_GATEWAY_REDIS_DB_PORT", "6379")
return LettuceConnectionFactory(redisHost, redisPort.toInt())
}
#Bean
fun redisTemplate(redisConnectionFactory: RedisConnectionFactory): RedisTemplate<String, String> {
val stringSerializer = StringRedisSerializer()
return RedisTemplate<String, String>()
.apply {
connectionFactory = redisConnectionFactory
keySerializer = stringSerializer
hashKeySerializer = stringSerializer
valueSerializer = stringSerializer
hashValueSerializer = stringSerializer
}
}
#Bean
fun redisMessageListenerContainer(
redisConnectionFactory: RedisConnectionFactory,
expirationListener: ExpirationListener
): RedisMessageListenerContainer {
val redisMessageListenerContainer = RedisMessageListenerContainer()
redisMessageListenerContainer.connectionFactory = redisConnectionFactory
redisMessageListenerContainer.addMessageListener(expirationListener, PatternTopic("__keyevent#*__:expired"))
return redisMessageListenerContainer
}
}
However, I don't know how to implement it with Spring data reactive redis.
In particular, since there is no addMessageListener() function in the RedisMessageListenerContainer, the predefined ExpirationListener could not be used.

Spring context doesn't load my class in unittest

I can't get my unit test to load my configuration class.
My test class is annotated:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles(profiles = "test")
#ContextConfiguration (classes = ClientConfiguration.class)
public class ClientConfigurationTest { ...
ClientConfiguration.class
#ConditionalOnProperty(value = "dirt.security.oauth2client", matchIfMissing = false)
#Configuration
#PropertySource(value = "classpath:oauth2client-${spring.profiles.active:local}.properties", ignoreResourceNotFound=true)
public class ClientConfiguration {
static {
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
#Bean
#ConfigurationProperties(prefix = "dirt.security.oauth2client.client")
ClientCredentialsResourceDetails clientConfig() {
return new ClientCredentialsResourceDetails() {
#Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
};
}
#Bean
#ConfigurationProperties(prefix = "dirt")
protected DirtClientConfig dirtClientConfig() {
return new DirtClientConfig();
}
#Bean
DirtRestTemplate restTemplate() {
DirtRestTemplate dirtRestTemplate =
new DirtRestTemplate(clientConfig(),
new DefaultOAuth2ClientContext(), dirtClientConfig());
dirtRestTemplate.setErrorHandler(new RestTemplateResponseErrorHandler());
return dirtRestTemplate;
}
}
None of the 3 beans get instantiated, and when I call this, it gets a dependecy error on one of the other beans
#Test
public void clientConfig() {
DirtRestTemplate results =
(DirtRestTemplate)context
.getAutowireCapableBeanFactory()
.createBean(DirtRestTemplate.class,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE,
true);
assertNotNull(results);
}

Spring WebFlux Route always returns 404

I am working on a simple project which uses Spring Boot 2 with Spring WebFlux using Kotlin.
I wrote test for my handler function (in which I mock the dependencies using Mockito).
However, it seems like my route function does not trigger the handler, as all of my requests return HTTP 404 NOT FOUND (even though the route is correct).
I have looked at various other projects to find out what how these tests are supposed to be written (here, here), but the problem persists.
The code is as follows (and can also be found on GitHub):
UserRouterTest
#ExtendWith(SpringExtension::class, MockitoExtension::class)
#Import(UserHandler::class)
#WebFluxTest
class UserRouterTest {
#MockBean
private lateinit var userService: UserService
#Autowired
private lateinit var userHandler: UserHandler
#Test
fun givenExistingCustomer_whenGetCustomerByID_thenCustomerFound() {
val expectedCustomer = User("test", "test")
val id = expectedCustomer.userID
`when`(userService.getUserByID(id)).thenReturn(Optional.ofNullable(expectedCustomer))
val router = UserRouter().userRoutes(userHandler)
val client = WebTestClient.bindToRouterFunction(router).build()
client.get()
.uri("/users/$id")
.accept(MediaType.ALL)
.exchange()
.expectStatus().isOk
.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
.expectBody(User::class.java)
}
}
User
#Entity
class User(var username : String, var password: String) {
#Id
val userID = UUID.randomUUID()
}
UserRepository
#Repository
interface UserRepository : JpaRepository<User, UUID>{
}
UserService
#Service
class UserService(
private val userRepository: UserRepository
) {
fun getUserByID(id: UUID): Optional<User> {
return Optional.of(
try {
userRepository.getOne(id)
} catch (e: EntityNotFoundException) {
User("test", "test")
}
)
}
fun addUser(user: User) {
userRepository.save(user)
}
}
UserHandler
#Component
class UserHandler(
private val userService: UserService
) {
fun getUserWithID(request: ServerRequest): Mono<ServerResponse> {
val id = try {
UUID.fromString(request.pathVariable("userID"))
} catch (e: IllegalArgumentException) {
return ServerResponse.badRequest().syncBody("Invalid user id")
}
val user = userService.getUserByID(id).get()
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(user))
}
}
UserRouter
#Configuration
class UserRouter {
#Bean
fun userRoutes(userHandler: UserHandler) = router {
contentType(MediaType.APPLICATION_JSON_UTF8).nest {
GET("/users/{userID}", userHandler::getUserWithID)
GET("") { ServerResponse.ok().build() }
}
}
}
EDIT
To route based on the presence of one or more query parameter (regardless of their values), we can do the following:
UserRouter
#Configuration
class UserRouter {
#Bean
fun userRoutes(userHandler: UserHandler) = router {
GET("/users/{userID}", userHandler::getUserWithID)
(GET("/users/")
and queryParam("username") { true }
and queryParam("password") { true }
)
.invoke(userHandler::getUsers)
}
}
Note that GET("/users/?username={username}", userHandler::getUsersWithUsername) does not work.
The way the router is configured - contentType(MediaType.APPLICATION_JSON_UTF8).nest - will only match requests that have this content type, so you would have to either remove the contentType prerequisite or change the test to include it
client.get()
.uri("/users/$id")
.accept(MediaType.ALL)
.header("Content-Type", "application/json;charset=UTF-8")
.exchange()
.expectStatus().isOk
.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
.expectBody(User::class.java)

Retrieve path variable on Spring Boot WebFlux (functional approach)

Let's say I have this router definition:
#Component
class PersonRouter(private val handler: PersonHandler) {
#Bean
fun router(): RouterFunction<ServerResponse> = router {
("/api/people" and accept(MediaType.APPLICATION_JSON_UTF8)).nest {
GET("/{id}") { handler.findById(it) }
}
}
And then this handler:
#Component
#Transactional
class PersonHandler(private val repository: PersonRepository) {
private companion object : KLogging()
#Transactional(readOnly = true)
fun findById(req: ServerRequest): Mono<ServerResponse> {
logger.info { "${req.method()} ${req.path()}" }
val uuid = ? // req.pathContainer().elements().last().value()
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(repository.findById(uuid)))
.switchIfEmpty(ServerResponse.notFound().build())
}
}
How do I access the identifier (what would be a #PathVariable id: String on a typical #RestController) from ServerRequest without doing black magic with regular expressions, string-heavy-lifting, and such things?
Ah! Found it!
It is by doing: req.pathVariable("id")
It was there all the time...in the official Spring Framework (Web Reactive) documentation!

Resources