# Step 5: Add receipt.png

You can use the Java Client Libraries to save non-RDF resources (e.g., **`.png`** , **`.pdf`** ) to your Pod.

For this part of the tutorial, the getting started app uses Inrupt’s Java client library to:

* Store a copy of the expense receipts to your Pod.
* Update the associated expense to link to the URLs of the receipts.

{% hint style="info" %}
You can find the complete code at [code](https://docs.inrupt.com/sdk/java-sdk/tutorial/step5/code "mention").
{% endhint %}

## Update **`application.properties`**

Add the following properties to the **`src/main/resources/application.properties`** file:

```json
spring.servlet.multipart.max-file-size=128KB
spring.servlet.multipart.max-request-size=128KB
```

## Modify **`Expense`** Class

1. Open **`Expense`** class file:

{% tabs %}
{% tab title="Java" %}
Open `src/main/java/com/example/gettingstarted/Expense.java`
{% endtab %}

{% tab title="Kotlin" %}
Open `src/main/kotlin/com/example/gettingstarted/Expense.kt`
{% endtab %}
{% endtabs %}

2. Add the **`java.util.*`** import statement:

{% tabs %}
{% tab title="Java" %}

```java
import java.util.*;
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
import java.util.*
```

{% endtab %}
{% endtabs %}

3. Add the predicate definition for the receipts in the **`Expense`** class:

{% tabs %}
{% tab title="Java" %}

```java
static IRI SCHEMA_ORG_IMAGE = rdf.createIRI("https://schema.org/image");
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
var SCHEMA_ORG_IMAGE: IRI = rdf.createIRI("https://schema.org/image")
```

{% endtab %}
{% endtabs %}

4. Update the **`Expense`** class constructor to include the receipts:

{% tabs %}
{% tab title="Java" %}

<pre class="language-java"><code class="lang-java">@JsonCreator
public Expense(@JsonProperty(&#x26;quot;identifier&#x26;quot;) final URI identifier,
               @JsonProperty(&#x26;quot;merchantProvider&#x26;quot;) String merchantProvider,
               @JsonProperty(&#x26;quot;expenseDate&#x26;quot;) Date expenseDate,
               @JsonProperty(&#x26;quot;description&#x26;quot;) String description,
               @JsonProperty(&#x26;quot;amount&#x26;quot;) BigDecimal amount,
               @JsonProperty(&#x26;quot;currency&#x26;quot;) String currency,
               @JsonProperty(&#x26;quot;category&#x26;quot;) String category,
<strong>               @JsonProperty(&#x26;quot;receipts&#x26;quot;) String[] receipts) {
</strong>    this(identifier);&#x3C;/strong>
    this.setRDFType(MY_RDF_TYPE_VALUE);
    this.setMerchantProvider(merchantProvider);
    this.setExpenseDate(expenseDate);
    this.setDescription(description);
    this.setAmount(amount);
    this.setCurrency(currency);
    this.setCategory(category);
<strong>    this.setReceipts(receipts);
</strong>}
</code></pre>

{% endtab %}

{% tab title="Kotlin" %}

<pre class="language-kotlin"><code class="lang-kotlin">@JsonCreator
constructor(
    @JsonProperty(&#x26;quot;identifier&#x26;quot;) identifier: URI,
    @JsonProperty(&#x26;quot;merchantProvider&#x26;quot;) merchantProvider: String?,
    @JsonProperty(&#x26;quot;expenseDate&#x26;quot;) expenseDate: Date,
    @JsonProperty(&#x26;quot;description&#x26;quot;) description: String?,
    @JsonProperty(&#x26;quot;amount&#x26;quot;) amount: BigDecimal?,
    @JsonProperty(&#x26;quot;currency&#x26;quot;) currency: String?,
    @JsonProperty(&#x26;quot;category&#x26;quot;) category: String?,
<strong>    @JsonProperty(&#x26;quot;receipts&#x26;quot;) receipts: Set&#x3C;String>?
</strong>) : this(identifier, rdf.createDataset(), Headers.empty()) {
    this.rdfType = MY_RDF_TYPE_VALUE
    this.merchantProvider = merchantProvider
    this.expenseDate = expenseDate
    this.description = description
    this.amount = amount
    this.currency = currency
    this.category = category
<strong>    this.receipts = receipts
</strong>}
</code></pre>

{% endtab %}
{% endtabs %}

5. Add the getter and setters for the receipts in the **`Expense`** class:

{% tabs %}
{% tab title="Java" %}

```java
public Set<String> getReceipts() {
    return subject.getReceipts();
}
// Note:: The setters first uses the getter, which returns a Set, and adds the receipt to the set.
public void addReceipt(String receipt) {
    subject.getReceipts().add(receipt);
}
public void setReceipts(String[] receipts) {
    subject.getReceipts().addAll(List.of(receipts));
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Note:: The setters first uses the getter, which returns a Set, and adds the receipt to the set.

var receipts: Set<String>?
    get() = subject.receipts
    set(receipts) {
        if (receipts != null) {
            subject.receipts.addAll(receipts)
        }
    }
fun addReceipt(receipt: String) {
    subject.receipts.add(receipt)
}

```

{% endtab %}
{% endtabs %}

6. Add getter for the receipts in the inner **`Node`** class:

{% tabs %}
{% tab title="Java" %}

```java
public Set<String> getReceipts() {
    return objects(SCHEMA_ORG_IMAGE, TermMappings::asIri, ValueMappings::iriAsString);
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val receipts: MutableSet<String>
    get() = objects(SCHEMA_ORG_IMAGE, TermMappings::asIri, ValueMappings::iriAsString)
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Note\
For more detail with regards to handling lists, see [https://github.com/inrupt/docs-gitbook/blob/main/sdk/java-sdk/tutorial/step5/broken-reference/README.md](https://github.com/inrupt/docs-gitbook/blob/main/sdk/java-sdk/tutorial/step5/broken-reference/README.md "mention").
{% endhint %}

## Modify **`ExpenseController`** Class

1. Open **`ExpenseController`** class file.

{% tabs %}
{% tab title="Java" %}
Open `src/main/java/com/example/gettingstarted/ExpenseController.java`
{% endtab %}

{% tab title="Kotlin" %}
Open `src/main/kotlin/com/example/gettingstarted/ExpenseController.kt`
{% endtab %}
{% endtabs %}

2. Add the following import statements:

{% tabs %}
{% tab title="Java" %}

```java
import com.inrupt.client.solid.SolidNonRDFSource;
import org.springframework.web.multipart.MultipartFile;
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
import com.inrupt.client.solid.SolidNonRDFSource
import org.springframework.web.multipart.MultipartFile
```

{% endtab %}
{% endtabs %}

3. Add the following method to handle the upload of non-RDF files:

{% tabs %}
{% tab title="Java" %}

```java

/**
 * Note 9: Stores a non-RDF resource to a Pod
 *
 * Using SolidNonRDFSource and the SolidSyncClient .create() method,
 * - Saves a non-RDF resource at the destinationURL.
 */
@PutMapping("**/resource/nonRDF/add**")
public String addNonRDFFile(@RequestParam(value = "destinationURL") String destinationURL,
                            @RequestParam(value = "file") MultipartFile file) {
    printWriter.println("In addNonRDFFile:: Save Non-RDF File to Pod.");
    try (final var fileStream = file.getInputStream()) {
        SolidNonRDFSource myNonRDFFile = new SolidNonRDFSource(URI.create(destinationURL), file.getContentType(), fileStream);
        return client.create(myNonRDFFile).getIdentifier().toString();
    } catch(PreconditionFailedException e1) {
        // Errors if the resource already exists
        printWriter.println(String.format("[%s] com.inrupt.client.solid.PreconditionFailedException in addNonRDFFile:: %s", e1.getStatusCode(), e1.getMessage()));
    } catch(ForbiddenException e2) {
        // Errors if user does not have access to create
        printWriter.println(String.format("[%s] com.inrupt.client.solid.ForbiddenException in addNonRDFFile:: %s", e2.getStatusCode(), e2.getMessage()));
    } catch(Exception e) {
        e.printStackTrace();
    }
    return null;
}

```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
/**
 * Note 9: Stores a non-RDF resource to a Pod
 *
 * Using SolidNonRDFSource and the SolidSyncClient's .create() method,
 * - Saves a non-RDF resource at the destinationURL.
 */
@PutMapping("**/resource/nonRDF/add**")
fun addNonRDFFile(
    @RequestParam(value = "destinationURL") destinationURL: String,
    @RequestParam(value = "file") file: MultipartFile
): String? {
    printWriter.println("In addNonRDFFile: Save Non-RDF File to Pod.")
    try {
        file.inputStream.use { fileStream ->
           val myNonRDFFile: SolidNonRDFSource = SolidNonRDFSource(URI.create(destinationURL), file.contentType, fileStream)
           return client.create(myNonRDFFile).identifier.toString()
        }
    } catch(e1: PreconditionFailedException) {
        // Errors if the resource already exists
        printWriter.println(String.format("[%s] com.inrupt.client.solid.PreconditionFailedException in addNonRDFFile:: %s", e1.statusCode, e1.localizedMessage))
    } catch(e2: ForbiddenException) {
        // Errors if user does not have access to create
        printWriter.println(String.format("[%s] com.inrupt.client.solid.ForbiddenException in addNonRDFFile:: %s", e2.statusCode, e2.localizedMessage))
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return ""
}

```

{% endtab %}
{% endtabs %}

4. Add the following method that uploads a receipt file and links it to the associated **`Expense`**.

{% tabs %}
{% tab title="Java" %}

```java
/**
 * Note 10: Stores a non-RDF resource (image of the receipt) to a Pod and Attach to an Expense
 * Using methods defined as part of getting started, addReceiptToExpense:
 * - Calls addNonRDFFile() to store the receipt to a Pod
 * - Calls getExpense() to fetch the associated Expense RDF resource.
 * - Calls the Expense's setter `addReceipt` to add the link to the saved receipt.
 * - Calls updateExpense() to save the updated Expense.
 */
@PutMapping("**/expenses/receipts/add**")
public Expense addReceiptToExpense(@RequestParam(value = "destinationURL") String destinationURL,
                                   @RequestParam(value = "file") MultipartFile file,
                                   @RequestParam(value = "expenseURL") String expenseURL) {
    printWriter.println("In addReceiptToExpense: Save Receipt File to Pod and Update Associated Expense.");
    try {
        String receiptLocation = addNonRDFFile(destinationURL, file);
        if (receiptLocation != null) {
            Expense expense = getExpense(expenseURL);
            expense.addReceipt(receiptLocation);
            return updateExpense(expense);
        } else {
            printWriter.println("Error adding receipt");
            return null;
        }
    } catch(ForbiddenException e2) {
        // Errors if user does not have access to read or update the Expense resource
        printWriter.println(String.format("[%s] com.inrupt.client.solid.ForbiddenException in addReceiptToExpense:: %s", e2.getStatusCode(), e2.getMessage()));
    } catch(Exception e) {
        e.printStackTrace();
    }
    return null;
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
/**
 * Note 10: Stores a non-RDF resource (image of the receipt) to a Pod and Attach to an Expense
 * Using methods defined as part of getting started, addReceiptToExpense:
 * - Calls addNonRDFFile() to store the receipt to a Pod
 * - Calls getExpense() to fetch the associated Expense RDF resource.
 * - Calls the Expense's setter `addReceipt` to add the link to the saved receipt.
 * - Calls updateExpense() to save the updated Expense.
 */
@PutMapping("**/expenses/receipts/add**")
fun addReceiptToExpense(
    @RequestParam(value = "destinationURL") destinationURL: String,
    @RequestParam(value = "file") file: MultipartFile,
    @RequestParam(value = "expenseURL") expenseURL: String
): Expense? {
    printWriter.println("In AddReceiptToExpense: Save Receipt File to Pod and Update Associated Expense.")
    val receiptLocation = addNonRDFFile(destinationURL, file)
    return if (!receiptLocation.isNullOrEmpty()) {
        val expense = getExpense(expenseURL)
        if (expense != null) {
            expense.addReceipt(receiptLocation)
            updateExpense(expense)
        } else {
            null
        }
    } else {
        printWriter.println("Error adding receipt")
        null
    }
}
```

{% endtab %}
{% endtabs %}
