hdpe / bowman Goto Github PK
View Code? Open in Web Editor NEWA Java library for accessing a JSON+HAL REST API
License: Apache License 2.0
A Java library for accessing a JSON+HAL REST API
License: Apache License 2.0
Hi there,
I have been using the project for creating simple clients for our JSON+HAL REST API but I cannot find how to map the search operations. Is it somewhere and I cannot find it or is it not yet supported?
i.e., for something like this:
curl localhost:8080/v1/items/search {
"_links" : {
"findByType" : {
"href" : "http://localhost:8080/v1/items/search/findByType{?type,page,size,sort}",
"templated" : true
},
"findById" : {
"href" : "http://localhost:8080/v1/items/search/findById{?Id}",
"templated" : true
},
"self" : {
"href" : "http://localhost:8080/v1/items/search"
}
}
}
Hi!
I am facing the following problem:
I am trying to request images from an API using Bowman.
The API gives me two linkes with the same relation name but the links themselve are different.
So βlet's say e.g.:
rel name is "get-image"
links: (among others):
rel name: get-image; link: /abc/image/cover/...
rel name: get-image; link: /abc/image/screenshot/...
The problem is that in that case Bowman just follows the first link and all other links with the same relation name are simply ignored.
I found out that the problem is located in method resolveForMethod
of class MethodLinkUriResolver
.
This method calls getLink
on the resource, which just returns the first link found with the given relation. All other links with the same relation are ignored. Beside getLink
, Spring Hateoas would also offer a method getLinks
which would return all links matching the given relation.
Is there a way to let Bowman follow all links with the given relation, not just the first one? Or any other ideas?
Thanks in advance!
Hello,
this not real requirement, more like a start of discussion. What do you think about dropping the support of older Java versions and increase the source level to 1.8?
Best Karl
Hi!
Is there any way to add embedded resources (_embedded property in HAL) to a bowman model? I did not find a way to do that yet.
If it's not supported by bowman (yet), are there any plans to add this feature to the library in future?
I think it should be something similar than the annotations for linked resources (@LinkedResource), e.g. defining an embedded resource by using an annotation @EmbeddedResource.
Thanks in advance.
Currently it is too hard to make some custom extensions to modify behavior of client depending on some specific need. For example, to make some minor changes inside one of GetterSetterMethodHandler method's (which might be our project-specific) it is required to fully copy-paste the whole GetterSetterMethodHandler class and ClientProxyFactory class (due to everything is private). Moreover, it is possible only by creating package uk.co.blackpepper.bowman in our project due to (due to package access for classes).
What needs to be changed:
Hi!, it might be nice some way to provide the restTemplate instead of the configurer.
I see there is a factory but didn't find a way to set it ?
I think I can workaround with something like this:
builder.setRestTemplateConfigurer(restTemplate -> restTemplate.getInterceptors()
.add((request, body, execution) -> {
request.getHeaders().add("Authorization", format("Bearer %s", oauth2RestTemplate.getAccessToken()));
return execution.execute(request, body);
}));
But probably more elegant just to be able to provide the factory, or the rest template it self. Don't you guys think ?
Following @altitudeinfosys's suggestion we should provide proper reference documentation for the project.
We'll aim to produce this is asciidoc format and have it automatically generate its HTML representation and publish to Github Pages as part of the build. We should publish the Javadoc too while we're at it.
Initial work on this started in docs.
I'd like to change the RestTemplate to a custom implementation of mine, but I only found a way to configure it using RestTemplateConfigurer.
Is there a way to accomplish this?
A change in Jackson 2.9.0 returns a NullPointerException at
(FasterXML/jackson-databind#1721)
InlineAssociationDeserializer(RestOperations restOperations, ClientProxyFactory proxyFactory) {
this((Class)null, restOperations, proxyFactory);
}
Should be this(Object.class,....)
Unfortunately, the Deserializer can not be extended, due the private constructor and package scoped dependency like RestOperation.
Hello,
We're currently using Bowman with SDR and have an issue regarding nullable linked resources.
Bowman throws an exception when trying to fetch a null linked-resource because the link is effectively absent. We have to wrap affected getters around try-catches, reducing the great transparency that Bowman initially offers.
This is not the case for inline resources as the property is set to "null" in the json.
I'm not sure if this is the correct behavior. It helps debugging typos but from a semantic point of view the absence of a link just denotes the absence of an association. Thus it may be better to return null if the link cannot be found ?
What's your opinion on this ?
I have a client app that is based on spring-boot-starter-parent:2.2.1.RELEASE and I have added bowman:0.8.0 to this application. At runtime I get this exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'createClientFactory' defined in class path resource [com/prodyna/pac/conference/frontend/client/BackendClientFactory.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [uk.co.blackpepper.bowman.ClientFactory]: Factory method 'createClientFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/hateoas/hal/Jackson2HalModule
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:645) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:475) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1287) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:636) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
... 63 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [uk.co.blackpepper.bowman.ClientFactory]: Factory method 'createClientFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/hateoas/hal/Jackson2HalModule
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:640) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
... 76 common frames omitted
Caused by: java.lang.NoClassDefFoundError: org/springframework/hateoas/hal/Jackson2HalModule
at uk.co.blackpepper.bowman.RestOperationsFactory.<init>(RestOperationsFactory.java:117) ~[bowman-client-0.8.0.jar:na]
at uk.co.blackpepper.bowman.ClientFactory.<init>(ClientFactory.java:42) ~[bowman-client-0.8.0.jar:na]
at uk.co.blackpepper.bowman.ClientFactory.<init>(ClientFactory.java:35) ~[bowman-client-0.8.0.jar:na]
at uk.co.blackpepper.bowman.Configuration.buildClientFactory(Configuration.java:166) ~[bowman-client-0.8.0.jar:na]
at com.prodyna.pac.conference.frontend.client.BackendClientFactory.createClientFactory(BackendClientFactory.java:25) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
... 77 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.hateoas.hal.Jackson2HalModule
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602) ~[na:na]
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na]
... 87 common frames omitted
The client factory does nothing special
@Bean
public ClientFactory createClientFactory() {
return Configuration.builder().setBaseUri(backendAddress.getURI()).build()
.buildClientFactory();
}
I compile using Java 13. Is this a known problem. Spring Boot 2.1.3 with bowman 0.3.0 was working properly
Do you have some reference at hand ?
Following implementation of #16, which allows resolution of templated links from method parameters, the templated link parameters and method parameters are assumed to be in the same order, i.e. for
{
"_links": {
"findByCriteria": {
"href": "http://blah/items/search/findByCriteria{?name,quest,favouriteColour}",
"templated": true
}
}
}
The method signature matching this endpoint must be exactly:
@LinkedResource Item findByCriteria(String name, String quest, String favouriteColour);
We should introduce a @LinkParam
annotation targeting method parameters to allow mapping of the method parameters to their corresponding templated link parameter, so we could write:
@LinkedResource Item findByCriteria(
@LinkParam("favouriteColour") String c,
@LinkParam("quest") String q,
@LinkParam("name") String n);
I'm getting the following
java.lang.NullPointerException
at uk.co.blackpepper.bowman.GetterSetterMethodHandler.resolveCollectionLinkedResource(GetterSetterMethodHandler.java:139)
at uk.co.blackpepper.bowman.GetterSetterMethodHandler.resolveLinkedResource(GetterSetterMethodHandler.java:116)
at uk.co.blackpepper.bowman.GetterSetterMethodHandler.invoke(GetterSetterMethodHandler.java:90)
at com.test.client.bowman.Account_$$_jvst416_0.getAccountEmails(Account_$$_jvst416_0.java)
at com.test.client.bowman.Bowman.test(Bowman.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
My Classes looks like:
package com.test.client.bowman;
import uk.co.blackpepper.bowman.annotation.LinkedResource;
import uk.co.blackpepper.bowman.annotation.RemoteResource;
import uk.co.blackpepper.bowman.annotation.ResourceId;
import java.net.URI;
import java.util.Set;
@RemoteResource("/accounts")
public class Account {
private URI id;
private String name;
private String timezone;
private boolean delegatedCompliance;
private Account parent;
private Set<AccountEmail> accountEmails;
@LinkedResource
public Set<AccountEmail> getAccountEmails() {
return accountEmails;
}
public void setAccountEmails(Set<AccountEmail> accountEmails) {
this.accountEmails = accountEmails;
}
@ResourceId
public URI getId() {
return id;
}
public String getName() {
return name;
}
public String getTimezone() {
return timezone;
}
public boolean isDelegatedCompliance() {
return delegatedCompliance;
}
public void setId(URI id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public void setDelegatedCompliance(boolean delegatedCompliance) {
this.delegatedCompliance = delegatedCompliance;
}
@LinkedResource
public Account getParent() {
return parent;
}
public void setParent(Account parent) {
this.parent = parent;
}
}
package com.test.client.bowman;
import uk.co.blackpepper.bowman.annotation.RemoteResource;
import uk.co.blackpepper.bowman.annotation.ResourceId;
import java.net.URI;
@RemoteResource("/accountEmails")
public class AccountEmail {
private URI id;
private String address;
@ResourceId
public URI getId() {
return id;
}
public void setId(URI id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
My Test
@Test
public void test() throws URISyntaxException {
ClientFactory factory = Configuration.builder()
.setBaseUri("http://foo.bar.com/v1")
.setClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactoryBasicAuth(new HttpHost("foo.bar.com", 80, "http")))
.setRestTemplateConfigurer((template) ->
template.getInterceptors().add(new BasicAuthInterceptor("admin", "secret"))
)
.build()
.buildClientFactory();
Client<Account> accounts = factory.create(Account.class);
Account account = accounts.get(new URI("http://foo.bar.com/v1/accounts/2dcd6f87-b6fd-4c20-8405-7e5432eb878a"));
assertThat(account.getName(), is("Test"));
assertThat(account.getAccountEmails().iterator().next().getAddress(), is("[email protected]")); //This throws a NPE
}
and my api works with the following urls
GET /v1/accounts/2dcd6f87-b6fd-4c20-8405-7e5432eb878a
{
"id": "2dcd6f87-b6fd-4c20-8405-7e5432eb878a",
"name": "Test",
"timezone": "Australia/Hobart",
"new": false,
"_links": {
"self": {
"href": "https://foo.bar.com/v1/accounts/2dcd6f87-b6fd-4c20-8405-7e5432eb878a"
},
"account": {
"href": "https://foo.bar.com/v1/accounts/2dcd6f87-b6fd-4c20-8405-7e5432eb878a{?projection}",
"templated": true
},
"accountEmails": {
"href": "https://foo.bar.com/v1/accounts/2dcd6f87-b6fd-4c20-8405-7e5432eb878a/accountEmails"
},
"parent": {
"href": "https://foo.bar.com/v1/accounts/2dcd6f87-b6fd-4c20-8405-7e5432eb878a/parent"
}
}
}
/v1/accounts/2dcd6f87-b6fd-4c20-8405-7e5432eb878a/accountEmails
{
"_embedded": {
"accountEmails": [
{
"id": "a5f0de4f-dc83-4f5e-9b41-4dd5b5cd5094",
"address": "[email protected]",
"new": false,
"_links": {
"self": {
"href": "https://foo.bar.com/v1/accountEmails/a5f0de4f-dc83-4f5e-9b41-4dd5b5cd5094"
},
"accountEmail": {
"href": "https://foo.bar.com/v1/accountEmails/a5f0de4f-dc83-4f5e-9b41-4dd5b5cd5094"
},
"account": {
"href": "https://foo.bar.com/v1/accountEmails/a5f0de4f-dc83-4f5e-9b41-4dd5b5cd5094/account"
}
}
}
]
},
"_links": {
"self": {
"href": "https://foo.bar.com/v1/accounts/2dcd6f87-b6fd-4c20-8405-7e5432eb878a/accountEmails"
}
}
}
When accessing @LinkedResource with parameters (like findAllByName(String name)) throws "wrong number of arguments" exception.
This occurs only when return type is Collection implementation. With single objects it works fine. Also Collections work fine when they are marked with @LinkedResource but have no parameters
The Bowman client is not compatible with Spring Boot versions 2.6 and later. The ResourceDeserializer
class references an EntityModel
constructor that was deprecated in Spring HATEOAS 1.1 and removed in Spring HATEOAS 1.4. Spring Boot 2.6 uses this new version of Spring HATEOAS.
class uk.co.blackpepper.bowman.ResourceDeserializer tried to access protected method org.springframework.hateoas.EntityModel.<init>(Ljava/lang/Object;Ljava/lang/Iterable;)V (uk.co.blackpepper.bowman.ResourceDeserializer and org.springframework.hateoas.EntityModel are in unnamed module of loader 'app')
java.lang.IllegalAccessError: class uk.co.blackpepper.bowman.ResourceDeserializer tried to access protected method org.springframework.hateoas.EntityModel.<init>(Ljava/lang/Object;Ljava/lang/Iterable;)V (uk.co.blackpepper.bowman.ResourceDeserializer and org.springframework.hateoas.EntityModel are in unnamed module of loader 'app')
at uk.co.blackpepper.bowman.ResourceDeserializer.deserialize(ResourceDeserializer.java:52)
at uk.co.blackpepper.bowman.ResourceDeserializer.deserialize(ResourceDeserializer.java:21)
at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4389)
at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:4345)
at uk.co.blackpepper.bowman.RestOperations.getResource(RestOperations.java:58)
at uk.co.blackpepper.bowman.Client.get(Client.java:80)
at com.example.issue.BowmanBootIssueTest.request(BowmanBootIssueTest.java:21)
build.gradle
plugins {
id 'org.springframework.boot' version '2.6.1' // Works if changed to 2.5.7
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'uk.co.blackpepper.bowman:bowman-client:0.9.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
import uk.co.blackpepper.bowman.annotation.RemoteResource;
@RemoteResource("/users")
public class User {
private Integer id;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
}
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import uk.co.blackpepper.bowman.Client;
import uk.co.blackpepper.bowman.ClientFactory;
import uk.co.blackpepper.bowman.Configuration;
import java.net.URI;
@SpringBootTest
class BowmanBootIssueTest {
@Test
void request() {
ClientFactory clientFactory = Configuration.builder()
.setBaseUri("http://reqres.in/api").build().buildClientFactory();
Client<User> userClient = clientFactory.create(User.class);
// Not actually HAL, but this still triggers the IllegalAccessError
userClient.get(URI.create("http://reqres.in/api/users/2"));
}
}
Hi!
The links to the reference documentation and API documentation do not work any more. They return a HTTP 404 status code.
Could you please update them?
Thanks in advance and best regards,
Simon
Hi,
we replaced our own handcrafted library with this awesome project. So fare we have not problems at all, except one. We would like to update our entities. I read the comment about problems with PUT operations.
The old library had no problems in updating the entities and the relations. To achieve this we handcrafted the list of URI's for the relations and used the RestTemplate with the HTTP PUT. As I understood from the code, you are doing this in more generic approach. That is the reason why we want to migrate to bowman.
Are there any plans to support PUT? Do you strongly advise against it?
Best Karl
As reported by @danapoklepovich, attempting to proxy a collection-valued method on an interface
@LinkedResource
List<Thing> things();
throws an NPE due to being unable to access the initial collection by calling the original method, as we do for concrete types.
Hi all,
We're using Bowman with the following scenario:
We think the correct behaviour should be that if you have set a LinkedResource to null, it shouldn't be overridden by a fetch when you invoke the getter.
Thanks!
Hi,
in case your entities using boolean and you prefer to use the 'is' prefix instead of the 'get' the generated proxy will ignore it. Please open up the method filter to include the 'is' prefix for processing.
See e.g. uk.co.blackpepper.bowman.test.it.SimpleEntityIT#canGetAndPutEntity
:
PUT of entity previously retrieved via GET sends:
PUT http://localhost:8080/simple-entities/15 : {"name":"updated","related":null,"handler":{}}
The handler
property present on the Javassist proxy should not be sent in the request.
There have not been any updates to this project in over two years, and the company that this project seems to be associated with (Black Pepper Software) no longer exists. Is this project still active, or is it now a dead project?
A few months ago, we made the difficult decision to close down Black Pepper in August.
Not really sure whether you would consider this a bug or a feature but I thought I'd raise it in case I can save other people some pain. I am using 0.5.0-RELEASE2 which I upgraded to so that we could use the new PATCH functionality.
The issue I am seeing is this:
After some investigation this appears to be because of a combination of two things:
Would be interested to get your thoughts on this and if you had any ideas for a possible work around / fix.
I am aware of #2 but that obviously relates to PUT operations rather than PATCH.
Thanks, Andy.
This is something more specific for Java 8 and the new Time API within Java 8. To support serialisation and deserialisation of LocalDateTime
and ZonedLocatDate
it is necessary to register additional modules to the Jackson ObjectMapper.
I suggest the same approach as for the ClientFactory
and RestTemplateCustomizer
. Enhance the Configuration
class and pass an external ObjectMapper
or even better a customizer to the underlying system. The default would be the current DefaultObjectMapperFactory
.
What do you think?
Hello,
When posting an entity with Bowman, the post method returns the entity with the resource id field populated via reflexion. However, if there are fields which are directly populated by the database (an auto-increment for example)n the field won't be filled in Bowman.
It's easy to bypass this problem by doing something like this :
public MyEntity postMyEntity(final MyEntity myEntity) {
URI myEntityURI= myEntityClient.post(myEntity);
return myEntityClient.get(myEntityURI);
}
I guess it could be usefull to implement something like this directly in Bowman ? What do you think ?
Thank you for this awesome library !
We should manage dependencies to the latest Spring Boot 2.x versions.
If this includes Jackson 2.9+, we should merge in whatever is in the jackson-2.9 branch and close the branch.
Since I upgraded my Springboot version to 3.1.3, I am getting below errors :-
class uk.co.blackpepper.bowman.ResourceDeserializer tried to access protected method 'void org.springframework.hateoas.EntityModel.(java.lang.Object, java.lang.Iterable)' (uk.co.blackpepper.bowman.ResourceDeserializer and org.springframework.hateoas.EntityModel are in unnamed module of loader 'app')
java.lang.NoSuchMethodError: 'org.springframework.http.HttpStatus org.springframework.web.client.HttpClientErrorException.getStatusCode()'
at uk.co.blackpepper.bowman.RestOperations.getResource(RestOperations.java:49)
at uk.co.blackpepper.bowman.Client.get(Client.java:80)
Do we have any support for bowman-client for latest springboot and java versions?
Currently what I am using:-
Hello,
The javassist library needs to be updated to the 3.25.0-GA version to avoid an NPE with Java 11.
Just want to throw that out there in case of a dependency upgrade.
I want to use bowman to access a hateoas api which is secured with OpenId Connect (oauth2). Is there a good way to add (or extend) authentication logic into bowman?
Regards,
Florian
Hello,
we are currently using Spring Boot 1.5.4 in our project and would like to use this awesome library. So fare it worked perfectly fine. Are there any plans to upgrade the dependencies to the latest versions?
Best Karl
Just wondering if there is any appetite for adding pagination support? E.g. configure things to use PagedResources instead of Resources and also to add some additional methods to follow first, next, prev and last links etc.
From my own perspective it would be nice to be able to have a getPage() method in the client where we could specify page size and offset etc.
As before I'm happy to do some work on this and issue a PR.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.