Skip to content

Commit

Permalink
Merge pull request #15 from hubrick/feature/allow-object-mapper-injec…
Browse files Browse the repository at this point in the history
…tion

allow injection of custom object mapper
  • Loading branch information
stritti authored Apr 28, 2017
2 parents ab16d5b + 0bbf382 commit 86de3f4
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 13 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ Table<Actor> actorTable = base.table("Actors", Actor.class);
Actor newActor = new Actor();
newActor.setName("Neuer Actor");
Actor test = actorTable.create(newActor);

```

Detailed example see [TableDestroyTest.java](https://github.com/Sybit-Education/airtable.java/blob/develop/src/test/java/com/sybit/airtable/TableCreateRecordTest.java)
Expand Down Expand Up @@ -370,6 +371,7 @@ We use [Gradle](https://gradle.org) to compile and package project:
+ build jar: `./gradlew jar` (The built JARs will be placed under `build/libs`.)

## Testing

There are JUnit tests and integration tests to verify the API.
The integration tests are based on the Airtable template [Movies](https://airtable.com/templates/groups-clubs-and-hobbies/exprTnrH3YV8Vv9BI/favorite-movies) which could be created in your account.
For testing, the JSON-responses are mocked by [WireMock](http://wiremock.org/).
Expand Down
1 change: 0 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ task integrationTest(type: Test) {
}
}


publishing {
publications {

Expand Down
138 changes: 138 additions & 0 deletions src/itest/java/com/sybit/airtable/TableSelectJacksonOMTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package com.sybit.airtable;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.mashape.unirest.http.ObjectMapper;
import com.sybit.airtable.exception.AirtableException;
import com.sybit.airtable.movies.ActorSerializedNames;
import com.sybit.airtable.movies.Movie;
import com.sybit.airtable.mock.WireMockBaseTest;
import org.apache.http.client.HttpResponseException;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.any;
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

/**
* Created by kobisuissa on 18/04/17.
*/
public class TableSelectJacksonOMTest extends WireMockBaseTest {

@Before
public void setup() throws AirtableException {
airtable.configure(new ObjectMapper() {

final com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();

@Override
public <T> T readValue(final String value, final Class<T> valueType) {
try {
return objectMapper.readValue(value, valueType);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Override
public String writeValue(final Object value) {
try {
return objectMapper.writeValueAsString(value);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
});
airtable.setEndpointUrl("http://localhost:8080/v0");

//set 404 as default
stubFor(any(anyUrl())
.atPriority(10)
.willReturn(aResponse()
.withStatus(404)
.withBody("{\"error\":{\"type\":\"NOT_FOUND\",\"message\":\"Not found\"}}")));

}

@Test
public void testSelectTable() throws AirtableException, HttpResponseException {

Base base = airtable.base("appe9941ff07fffcc");

List<Movie> retval = base.table("Movies", Movie.class).select();
assertNotNull(retval);
assertEquals(10, retval.size());
Movie mov = retval.get(0);
assertEquals("Sister Act", mov.getName());
}

@Test
public void testSelectTableMaxRecords() throws AirtableException, HttpResponseException {

Base base = airtable.base("appe9941ff07fffcc");

List<Movie> retval = base.table("Movies", Movie.class).select(2);
assertNotNull(retval);
assertEquals(2, retval.size());
Movie mov = retval.get(0);
assertEquals("Sister Act", mov.getName());
}

@Test
public void testSelectTableSorted() throws AirtableException, HttpResponseException {

Base base = airtable.base("appe9941ff07fffcc");
Table table = base.table("Movies", Movie.class);

List<Movie> retval = table.select(new Sort("Name", Sort.Direction.asc));
assertNotNull(retval);
assertEquals(10, retval.size());
Movie mov = retval.get(0);
assertEquals("Billy Madison", mov.getName());

retval = table.select(new Sort("Name", Sort.Direction.desc));
assertNotNull(retval);
assertEquals(10, retval.size());
mov = retval.get(0);
assertEquals("You've got Mail", mov.getName());

}

@Test
public void testSelectTableView() throws AirtableException, HttpResponseException {

Base base = airtable.base("appe9941ff07fffcc");

List<Movie> retval = base.table("Movies", Movie.class).select("Main View");
assertNotNull(retval);
assertEquals(10, retval.size());
Movie mov = retval.get(0);
assertEquals("The Godfather", mov.getName());
}

@Test(expected = AirtableException.class)
public void testSelectNonExistingTable() throws AirtableException, HttpResponseException {

Base base = airtable.base("appe9941ff07fffcc");

List<Movie> retval = base.table("NotExists", Movie.class).select();
assertNotNull(retval);
}

@Test
public void testSelectWithSerializedNames() throws AirtableException, HttpResponseException {

Base base = airtable.base("appe9941ff07fffcc");

List<ActorSerializedNames> retval = base.table("SerializedNames", ActorSerializedNames.class).select();
assertNotNull(retval);
assertEquals("Marlon Brando", retval.get(0).getName());
}

}
61 changes: 50 additions & 11 deletions src/main/java/com/sybit/airtable/Airtable.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package com.sybit.airtable;


import com.mashape.unirest.http.ObjectMapper;
import com.mashape.unirest.http.Unirest;
import com.sybit.airtable.converter.ListConverter;
import com.sybit.airtable.converter.MapConverter;
Expand Down Expand Up @@ -54,11 +55,24 @@ public class Airtable {
* Configure, <code>AIRTABLE_API_KEY</code> passed by Java property, enviroment variable
* or within credentials.properties.
*
* @return configured Airtable object.
* @return An Airtable instance configured with GsonObjectMapper
* @throws com.sybit.airtable.exception.AirtableException Missing API-Key
*/
@SuppressWarnings("UnusedReturnValue")
public Airtable configure() throws AirtableException {
return this.configure(new GsonObjectMapper());
}

/**
* Configure, <code>AIRTABLE_API_KEY</code> passed by Java property, enviroment variable
* or within credentials.properties.
*
* @param objectMapper A custom ObjectMapper implementation
* @return An Airtable instance configured with supplied ObjectMapper
* @throws com.sybit.airtable.exception.AirtableException Missing API-Key
*/
@SuppressWarnings("UnusedReturnValue")
public Airtable configure(ObjectMapper objectMapper) throws AirtableException {

LOG.info( "System-Property: Using Java property '-D" + AIRTABLE_API_KEY + "' to get apikey.");
String airtableApi = System.getProperty(AIRTABLE_API_KEY);
Expand All @@ -71,7 +85,7 @@ public Airtable configure() throws AirtableException {
airtableApi = getCredentialProperty(AIRTABLE_API_KEY);
}

return this.configure(airtableApi);
return this.configure(airtableApi, objectMapper);
}


Expand All @@ -80,12 +94,25 @@ public Airtable configure() throws AirtableException {
* Configure Airtable.
*
* @param apiKey API-Key of Airtable.
* @return
* @return An Airtable instance configured with GsonObjectMapper
* @throws com.sybit.airtable.exception.AirtableException Missing API-Key
*/
@SuppressWarnings("WeakerAccess")
public Airtable configure(String apiKey) throws AirtableException {
return configure(new Configuration(apiKey, Configuration.ENDPOINT_URL));
return configure(apiKey, new GsonObjectMapper());
}

/**
* Configure Airtable.
*
* @param apiKey API-Key of Airtable.
* @param objectMapper A custom ObjectMapper implementation
* @return
* @throws com.sybit.airtable.exception.AirtableException Missing API-Key
*/
@SuppressWarnings("WeakerAccess")
public Airtable configure(String apiKey, ObjectMapper objectMapper) throws AirtableException {
return configure(new Configuration(apiKey, Configuration.ENDPOINT_URL), objectMapper);
}

/**
Expand All @@ -96,6 +123,19 @@ public Airtable configure(String apiKey) throws AirtableException {
*/
@SuppressWarnings("WeakerAccess")
public Airtable configure(Configuration config) throws AirtableException {
return configure(config, new GsonObjectMapper());
}


/**
*
* @param config
* @param objectMapper A custom ObjectMapper implementation
* @return
* @throws com.sybit.airtable.exception.AirtableException Missing API-Key or Endpoint
*/
@SuppressWarnings("WeakerAccess")
public Airtable configure(Configuration config, ObjectMapper objectMapper) throws AirtableException {
if(config.getApiKey() == null) {
throw new AirtableException("Missing Airtable API-Key");
}
Expand All @@ -113,22 +153,21 @@ public Airtable configure(Configuration config) throws AirtableException {
setProxy(config.getEndpointUrl());

// Only one time
Unirest.setObjectMapper(new GsonObjectMapper());
Unirest.setObjectMapper(objectMapper);


// Add specific Converter for Date
DateTimeConverter dtConverter = new DateConverter();
ListConverter lConverter = new ListConverter();
MapConverter thConverter = new MapConverter();

lConverter.setListClass(Attachment.class);
thConverter.setMapClass(Thumbnail.class);
dtConverter.setPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

ConvertUtils.register(dtConverter, Date.class);
ConvertUtils.register(lConverter, List.class);
ConvertUtils.register(thConverter, Map.class);


return this;
}
Expand All @@ -142,8 +181,8 @@ public Airtable configure(Configuration config) throws AirtableException {
private void setProxy(String endpointUrl) {
final String httpProxy = System.getenv("http_proxy");
if(httpProxy != null
&& (endpointUrl.contains("127.0.0.1")
|| endpointUrl.contains("localhost"))) {
&& (endpointUrl.contains("127.0.0.1")
|| endpointUrl.contains("localhost"))) {
LOG.info("Use Proxy: ignored for 'localhost' ann '127.0.0.1'");
Unirest.setProxy(null);
} else if(httpProxy != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,4 @@ public void setMapClass(Class<Thumbnail> aClass) {
public Class getMapClass(){
return this.mapClass;
}

}
1 change: 1 addition & 0 deletions src/test/java/com/sybit/airtable/movies/Actor.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package com.sybit.airtable.movies;



import com.sybit.airtable.movies.*;
import com.google.gson.annotations.SerializedName;
import com.sybit.airtable.vo.Attachment;
Expand Down
1 change: 1 addition & 0 deletions src/test/java/com/sybit/airtable/movies/Movie.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package com.sybit.airtable.movies;


import com.sybit.airtable.movies.*;
import com.google.gson.annotations.SerializedName;
import com.sybit.airtable.vo.Attachment;
Expand Down

0 comments on commit 86de3f4

Please sign in to comment.