Dependencies for Spring Integration Amqp in Spring Boot - spring

In order to use Spring Integration Amqp in a Spring Boot application, what are the dependencies I need to include?
Spring Boot version is 2.0.5.
Current dependencies I have are spring-boot-starter-integration and spring-integration-amqp
Error messages are classes like SimpleMessageListenerContainer and AmqpInboundChannelAdapter are not found on the classpath.
UPDATE:
My build.gradle entries --
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE")
}
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-integration')
compile('org.springframework.boot:spring-boot-starter-amqp')
compile('org.springframework.integration:spring-integration-amqp')
testCompile('org.springframework.boot:spring-boot-starter-test')
}

I had to add the following dependencies to resolve the classes in question (the last in the list did it, using latest spring initalizr, spring-boot 2.0.5)
dependencies {
implementation('org.springframework.boot:spring-boot-starter-amqp')
implementation('org.springframework.boot:spring-boot-starter-integration')
testImplementation('org.springframework.boot:spring-boot-starter-test')
compile 'org.springframework.integration:spring-integration-amqp'
}
To be fair, this answer was already given, just not for gradle.
I am using gradle 4.10.2 on a linux machine, spring-boot initialzr with the options RabbitMQ and Spring-Integration. Here are the changed files:
build.gradle
buildscript {
ext {
springBootVersion = '2.0.5.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
implementation('org.springframework.boot:spring-boot-starter-amqp')
implementation('org.springframework.boot:spring-boot-starter-integration')
testImplementation('org.springframework.boot:spring-boot-starter-test')
compile 'org.springframework.integration:spring-integration-amqp'
}
Implementation of Example 12.2.1 Configuring with Java Configuration from the Spring Integration docs:
package com.example.integrationamqp;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter;
import org.springframework.integration.amqp.inbound.AmqpInboundGateway;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
#SpringBootApplication
public class IntegrationAmqpApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(IntegrationAmqpApplication.class)
.web(WebApplicationType.NONE)
.run(args);
}
#Bean
public MessageChannel amqpInputChannel() {
return new DirectChannel();
}
#Bean
public AmqpInboundChannelAdapter inbound(SimpleMessageListenerContainer listenerContainer,
#Qualifier("amqpInputChannel") MessageChannel channel) {
AmqpInboundChannelAdapter adapter = new AmqpInboundChannelAdapter(listenerContainer);
adapter.setOutputChannel(channel);
return adapter;
}
#Bean
public SimpleMessageListenerContainer container(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container =
new SimpleMessageListenerContainer(connectionFactory);
container.setQueueNames("foo");
container.setConcurrentConsumers(2);
// ...
return container;
}
#Bean
#ServiceActivator(inputChannel = "amqpInputChannel")
public MessageHandler handler() {
return new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
System.out.println(message.getPayload());
}
};
}
}

Add this dependency:
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
And are you sure you have this one?:
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-amqp</artifactId>

Related

MapStruct not injected in Kotlin project

I am trying to create a project with current Kotlin, MapStruct and Java using Spring-Boot folowing some online examples, as I am new to MapStruct, however I am not able to inject the mapper into my service. Both Idea and Gradle (in build task test) complain that no bean has been found (UnsatisfiedDependencyException). Googling didn't help. What am I missing?
MWE:
build.gradle.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.7.4"
id("io.spring.dependency-management") version "1.0.14.RELEASE"
kotlin("jvm") version "1.7.20"
kotlin("plugin.spring") version "1.7.20"
kotlin("plugin.jpa") version "1.7.20"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testImplementation("org.springframework.boot:spring-boot-starter-test")
implementation("org.mapstruct:mapstruct:1.5.3.Final")
annotationProcessor("org.mapstruct:mapstruct-processor:1.5.3.Final")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
DemoAppllication.kt
package com.example.demo
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
#SpringBootApplication
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
App.kt
package com.example.demo
import org.mapstruct.Mapper
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
import org.springframework.stereotype.Service
import javax.persistence.*
#Entity
#Table(name = "items")
class Item(#Id var id: Int = 0)
data class ItemDto(val id: Int)
#Repository
interface ItemRepo : JpaRepository<Item, Int>
#Mapper(componentModel = "spring")
interface ItemMapper {
fun entToDto(item: Item) : ItemDto
fun entsToDtos(items: List<Item>) : List<ItemDto>
fun dtoToEnt(itemDto: ItemDto) : Item
}
#Service
class Srvc(private val itemMapper: ItemMapper, // XXX: no bean found for this one
private val repo: ItemRepo)
{
fun items() = itemMapper.entsToDtos(repo.findAll())
}
// controller skipped
Kapt is in maintenance mode! See example: https://github.com/mapstruct/mapstruct-examples/tree/main/mapstruct-kotlin
plugin {
// ...
kotlin("kapt")
// ...
}
dependencies {
// ...
kapt("org.mapstruct:mapstruct-processor:$version")
implementation("org.mapstruct:mapstruct:$version")
// ...
}
EDIT (by mpts.cz — for future me or anyone as new to Mapstruct and/or Gradle as I am):
use plugin kotlin("kapt")
replace annotationProcessor("org.mapstruct:mapstruct-processor:$version")
with kapt("org.mapstruct:mapstruct-processor:$version")
put the previous line before implementation("org.mapstruct:mapstruct:$version")
With these changes all seems to work smoothly. Thanks Numichi!

How to listen to two RabbitMQ queues with spring-cloud-stream

I've got a working application that listens to a single RabbitMQ queue.
However, when I add another bean that consumes messages and try to bind that to another queue, neither of the queues are created in RabbitMQ and when creating them manually no messages are consumed from these queues.
Small kotlin project I created to demonstrate the issue:
#SpringBootApplication
class SpringCloudStreamTwoRabbitConsumersApplication
fun main(args: Array<String>) {
runApplication<SpringCloudStreamTwoRabbitConsumersApplication>(*args)
}
package com.example.springcloudstreamtworabbitconsumers
import org.springframework.context.annotation.Bean
import org.springframework.messaging.Message
import org.springframework.stereotype.Component
import java.util.function.Consumer
#Component
class Listener1Config {
#Bean
fun listener1(): Consumer<Message<String>> {
return Consumer { input -> println(input) }
}
}
package com.example.springcloudstreamtworabbitconsumers
import org.springframework.context.annotation.Bean
import org.springframework.messaging.Message
import org.springframework.stereotype.Component
import java.util.function.Consumer
#Component
class Listener2Config {
#Bean
fun listener2(): Consumer<Message<String>> {
return Consumer { input -> println(input) }
}
}
application.properties:
# Rabbit properties
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
# Listener 1
spring.cloud.stream.bindings.listener1-in-0.destination=exchange1
spring.cloud.stream.bindings.listener1-in-0.group=exchange1-queue
spring.cloud.stream.rabbit.bindings.listener1-in-0.consumer.queueNameGroupOnly=true
spring.cloud.stream.rabbit.bindings.listener1-in-0.consumer.binding-routing-key-delimiter=,
spring.cloud.stream.rabbit.bindings.listener1-in-0.consumer.bindingRoutingKey=binding.key.1,binding.key.1.1
spring.cloud.stream.rabbit.bindings.listener1-in-0.consumer.exchangeType=topic
spring.cloud.stream.rabbit.bindings.listener1-in-0.consumer.autoBindDlq=true
# Listener 2
spring.cloud.stream.bindings.listener2-in-0.destination=exchange2
spring.cloud.stream.bindings.listener2-in-0.group=exchange2-queue
spring.cloud.stream.rabbit.bindings.listener2-in-0.consumer.queueNameGroupOnly=true
spring.cloud.stream.rabbit.bindings.listener2-in-0.consumer.binding-routing-key-delimiter=,
spring.cloud.stream.rabbit.bindings.listener2-in-0.consumer.bindingRoutingKey=binding.key.2,binding.key.2.1
spring.cloud.stream.rabbit.bindings.listener2-in-0.consumer.exchangeType=topic
spring.cloud.stream.rabbit.bindings.listener2-in-0.consumer.autoBindDlq=true
build.gradle.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.4.3"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.4.30"
kotlin("plugin.spring") version "1.4.30"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8
repositories {
mavenCentral()
}
extra["springCloudVersion"] = "2020.0.1"
dependencies {
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.springframework.cloud:spring-cloud-stream")
implementation("org.springframework.cloud:spring-cloud-stream-binder-rabbit")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
}
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "1.8"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
When I comment out one of the listener beans the other one works as expected. However with both beans active, no queue is created in RabbitMQ, nor are messages read from the queues if I create them manually and send messages to the exchange.
What am I doing wrong here?
The framework can only detect a single function. When you have multiple, you need to specify:
spring.cloud.function.definition=listener1;listener2
https://docs.spring.io/spring-cloud-stream/docs/3.1.1/reference/html/spring-cloud-stream.html#spring_cloud_function
In the event you only have single bean of type java.util.function.[Supplier/Function/Consumer], you can skip the spring.cloud.function.definition property, since such functional bean will be auto-discovered. However, it is considered best practice to use such property to avoid any confusion.

How to build a SOAP WS with Apache CXF + Spring Boot in Gradle?

The assignment was simple: A SOAP web service implemented with spring boot, JDBC using Gradle.
After some time looking around the discovery was made that "Spring-WS" only works with a contract-first development style.
And we didn't want that, so we dig a little further and found out what we already know, we had to use Apache CXF for a Contract Last development style.
So off we went to search, code and test; but once the data access and facades were done we couldn’t figure out how to wire the Apache CXF WS with the Spring Boot service Façade.
So… how is it done?
This is more of a rhetorical question, because after looking around we could not find an example of Spring Boot & Apache CXF working seamlessly together, so for anyone who may be searching, here is a simple example.
First the dependencies used by the Gradle project
build.gradle file
buildscript {
ext {
springBootVersion = '2.0.1.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'
group = 'com.telcel'
version = '0.0.1-RC'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
configurations {
providedRuntime
}
dependencies {
// Apache CXF
compile(group: 'org.apache.cxf', name: 'cxf-spring-boot-starter-jaxws', version: '3.1.15') {
exclude(module: 'spring-boot-starter-tomcat')
}
// JDBC support
compile('org.springframework.boot:spring-boot-starter-jdbc')
// embedded servlet container
compile group: 'org.springframework.boot', name: 'spring-boot-starter-undertow', version: '1.5.4.RELEASE'
runtime group: 'com.ibm.informix', name: 'jdbc', version: '4.10.10.0'
testCompile('org.springframework.boot:spring-boot-starter-test')
testRuntime group: 'com.ibm.informix', name: 'jdbc', version: '4.10.10.0'
}
Then, we need some basic things for the CXF config.
application.properties file:
cxf.path=/service
server.address=0.0.0.0
We needed Spring Boot to create a CXF Endpoint, and we also needed that Endpoint to use our Spring aware Facade... this is where the wiring magic happened.
WebServiceConfig.java
package com.telcel.validaserie;
import com.telcel.validaserie.ui.ValidaSerieEndpoint;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.xml.ws.Endpoint;
#Configuration
public class WebServiceConfig {
#Autowired
private Bus bus;
#Autowired
private ValidaSerieEndpoint validaSerieEndpoint;
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(bus, validaSerieEndpoint);
endpoint.publish("/");
return endpoint;
}
}
Notice the autowired ValidaSerieEndpoint that goes as a parameter into the EndpointImpl constructor, that's the trick, plain simple.
Finally just a simple web service implementation exposed as a Spring Bean (notice the Spring #Service stereotype)
ValidaSerieEndpoint.class
package com.telcel.validaserie.ui;
import com.telcel.validaserie.servicios.ValidaSeriesFacade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
#Service
#WebService
public class ValidaSerieEndpoint {
#Autowired
private ValidaSeriesFacade validaSeriesFacade;
#WebMethod
public String validaTelefonoIccid(#WebParam(name = "iccid") String iccid) {
return validaSeriesFacade.validaTelefonoIccid(iccid);
}
#WebMethod
public String validaTelefonoImei(#WebParam(name = "imei") String imei) {
return validaSeriesFacade.validaTelefonoImei(imei);
}
#WebMethod
public int validaFacturaIccid(#WebParam(name = "iccid") String iccid, #WebParam(name = "fuerza-venta") String fuerzaVenta) {
return validaSeriesFacade.validaFacturaIccid(iccid, fuerzaVenta);
}
#WebMethod
public int validaFacturaImei(#WebParam(name = "imei") String imei, #WebParam(name = "fuerza-venta") String fuerzaVenta) {
return validaSeriesFacade.validaFacturaImei(imei, fuerzaVenta);
}
}
And that's it quite simple after you look at it... hope this helps.

Unable to call spring boot application service when deployed to tomcat server.

I have a SpringBootApp that I can run in eclipse by right-clinging and then selecting Run as -> Java Application. However, when I build a .war file and deploy it to my tomcat server. The console looks as though the application should have deployed but I'm unable to hit my rest services. I'm getting a 404 error. I really have no clue why it is not working so if anyone knows a solution could you explain why... Also, when I look in my war file i see all the classes files needed to deploy the application.
You can download the code github.
Controller:
package com.sample.pkg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
#Controller
#ComponentScan("com.sample.pkg")
public class SampleController {
#Autowired
SampleComponent component;
#RequestMapping("/sendOption")
public String update(#RequestParam(value = "option") String option) {
if (option.equalsIgnoreCase("option1")) {
component.updateStatus(true);
return "Something was updated";
} else if (option.equalsIgnoreCase("option2")) {
component.updateStatus(false);
return "Something else was updated";
}
return "You have entered in an option that is invalid. Please enter a valid option.";
}
#RequestMapping("/getOption")
public String control() {
if (component.getStatus()) {
return "option1";
} else if (!component.getStatus()) {
return "option2";
}
return "error";
}
}
Application.java
package com.chicken.door;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.PropertySource;
#SpringBootApplication
#PropertySource("classpath:application.properties")
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.3.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'war'
war {
baseName = 'gs-spring-boot'
version = '0.1.0'
}
jar {
baseName = 'gs-spring-boot'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-actuator")
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testCompile("org.springframework.boot:spring-boot-starter-test")
}
Output:
2017-07-18 21:32:13.246 INFO 947 --- [ main] com.sample.pkg.Application : Started Application in 10.6 seconds (JVM running for 10.976)

Gradle build with fatJar plugin and SpringBoot application gives 'Application startup failed'

Everything was working fine when starting my app using Intellij. But when I made fatJar (with gradle plugin: eu.appsatori.fatjar) and execute:
java -jar myapp.jar
I'm getting something like this:
11:41:01.224 [main] ERROR org.springframework.boot.SpringApplication - Application startup failed
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [my.testing.MyAppMain]; nested exception is java.lang.IllegalArgumentException: No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.
at org.springframework.context.annotation.ConfigurationClassParser.processDeferredImportSelectors(ConfigurationClassParser.java:482)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:184)
...
It looks like it didn't found auto configuration classes in META-INF/spring.factories.
How to add this file? And what should be the content of it?
I've got following build script:
apply plugin: "java";
apply plugin: "idea";
apply plugin: 'application'
apply plugin: 'eu.appsatori.fatjar'
apply plugin: 'org.springframework.boot'
repositories {
mavenCentral()
}
buildscript {
ext {
springBootVersion = '1.4.3.RELEASE'
}
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
}
}
sourceSets {
main {
java {
srcDir 'src/main/java'
}
resources {
srcDir 'src/main/resources'
}
}
test {
java {
srcDir 'src/test/java'
}
}
}
fatJar {
manifest {
attributes("Main-Class": 'my.testing.MyAppMain')
}
exclude 'META-INF/*.DSA'
exclude 'META-INF/*.SF'
exclude 'META-INF/*.RSA'
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter-jdbc'
runtime 'mysql:mysql-connector-java'
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
And my example code is:
package my.testing;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
#SpringBootApplication
public class MyAppMain {
private ConfigurableApplicationContext springContext;
#Autowired
private SimpleDao dao;
public static void main(String[] args) throws Exception {
MyAppMain test = new MyAppMain();
try {
test.init();
test.doWhatYouGotToDo();
} finally {
test.stop();
}
}
private void doWhatYouGotToDo() {
System.out.println("Auto-wired dao: " + dao.hashCode());
System.out.println("Auto-wired jdbcTemplate: " + dao.jdbcTemplate.hashCode());
}
private void init() throws Exception {
springContext = SpringApplication.run(MyAppMain.class);
springContext.getAutowireCapableBeanFactory().autowireBean(this);
}
private void stop() throws Exception {
springContext.close();
}
}
#Component
class SimpleDao {
#Autowired
JdbcTemplate jdbcTemplate;
}
application.properties file:
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/some_db?useSSL=false&serverTimezone=UTC
spring.datasource.username = some_user
spring.datasource.password = some_pass
NOTE: This question is based on SpringBoot - making jar files - No auto configuration classes found in META-INF/spring.factories
where are all answers are referring to building with Maven. Please put only answers related to Gradle here.
Although I mostly use Maven for Spring and Gradle for Android, but here is the gradle way for a Spring project:
gradle clean build
gradle bootRepackage
Result:
Here is my build.gradle file:

Resources