Coder Social home page Coder Social logo

bowman's People

Contributors

aelstad avatar andye2004 avatar ansonator avatar danapoklepovich avatar eepstein avatar hdpe avatar markhobson avatar nwholloway avatar vid14114 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bowman's Issues

Support for search operations

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"
    }
  }
}

Follow all links with the same relation, not just the first one

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!

Java 8 support

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

Support for _embedded resources

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.

Project isn't extendable

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:

  1. Make all classes public
  2. Make most of (or almost all) private class fields (or getters for them) protected and most of (or almost all) private methods protected
  3. Consider to simplify way to instantiate objects - reduce number of factories, builders etc.

Some way to set an OAuth2RestTemplate ?

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 ?

Provide reference documentation

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.

Changing the RestTemplate

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?

Fetching null linked-resource throws exception

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 ?

spring-boot 2.2.1 and bowman 0.8.0 -> ClassNotFoundException

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

Support mapping of method params to templated link params

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);

NPE when fetching related collection with Spring Data generated API

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"
    }
  }
}





LinkedResource throws "wrong number of arguments" exception

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

Client incompatible with Spring Boot 2.6

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)

To Reproduce

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"));
    }
}

Support for PUT operations

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

LinkedResource not supporting setting null as valid value

Hi all,

We're using Bowman with the following scenario:

  • An Object A that has a nullable LinkedResource Object B (both projects UI and backend)
  • Having an instance of A that has a not null instance of B, when setting a.setB(null) it invokes the LinkedResourceMethodHandler.invokeSetterMethod, which sets the value to null (so far so good)
  • When a.getB() is invoked, it will invoke LinkedResourceMethodHandler.invokeAnnotatedMethod, which fetches the value again from the backend because the LinkedResource (B) is null.
  • So, we can't set the LinkedResource to null.

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!

Boolean getter 'is' is not support by Javassist Proxy

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.

Re-submitting a proxy sends extraneous 'handler' property

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.

Serialising patch requests not working correctly

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:

  1. I have an entity being served up by a Spring Data REST service that contains a linked resource.
  2. I modify the entity in a web-app to update the linked resource to point to a different resource.
  3. When the request is serialised to send to the SDR service it always serialises the 'old' linked resource.

After some investigation this appears to be because of a combination of two things:

  1. When the resource setter method is called it does actually update the underlying instance BUT the linked resources contained in the LinkedResourceMethodHandler are never updated.
  2. The handler chain has the LinkedResourceMethodHandler in the chain BEFORE the getter handler which means that it returns the resource from the list in the LinkedResourceMethodHandler which is the original linked resource.

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.

Open internal ObjectMapper or Customizer to add additional Modules

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?

Retrieve the database object when posting an entity

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 !

Manage dependencies to Spring Boot 2

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.

Bowman Client not supporting Spring boot 3.x

Since I upgraded my Springboot version to 3.1.3, I am getting below errors :-

  1. 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')

  2. 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:-

uk.co.blackpepper.bowman bowman-client 0.9.0

Java 11 support

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.

How to handle authentication?

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

Add support for pagination

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.