Code Monkey home page Code Monkey logo

hydra-java's People

Contributors

ceefour avatar dschulten avatar fkleon avatar nibe avatar sotty 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hydra-java's Issues

Using hydra-java without Spring

It would be nice to use hydra-java to render responses from a service that uses plain Jax-RS, with Jackson, for example. In that sense, I found out that this can be accomplished if we remove the dependencies on spring from the class 'JacksonHydraModule'. So, If you like, I can send a pull request containing the refactoring of this class, splitting it in two, one with the current code without the spring dependencies and the other as a subclass of the first plus the dependencies on spring.
What do you think?

Handle incoming json-ld in expanded form

Right now we only understand json requests whose attributes have a name equivalent on the target java bean. Enhance this so that an incoming json-ld object is mapped based on the expanded form.

I suppose this project is dead, yes?

Hi dschulten,

I'm relating to #18 .

I'm also very doubtful it was a good decision to entirely rely on Spring HATEOAS for the backing model which is then mapped to Hydra in a hardcoded way. For Links that mapping is done in a seemingly never ending if-else chain in LinkListSerializer. This class alone I consider highly problematic with regards to judging the readiness of this framework to support the adoption of Hydra in the Java ecosystem. Unfortunately hydra-java is the only listed Java implementation on hydra-cg.com, making it look a bit like THE Hydra reference implementation, which it clearly isn't. At least not as long as the actual Hydra model lives in a bunch of highly nested if/else branches with TODOs galore on them. Yes I understand it's all in testing but that's still no excuse to leave it like this.

That's all well and good if hydra-java is just some random Hydra implementation on GitHub serving mostly the creators own needs.
At the same time I'm not sure how many visitors looking for a Java Hydra backend implementation came here, noticed that...

  1. The Hydra vocabulary is not actually modelled, let alone properly exposed.
  2. The project has multiple hard dependencies to Spring. Where I work Spring in general is considered enterprise legacy cruft.
  3. Is seems conceptually opaque and written in a less than expressive code style in its most vital parts.

... and then left immediately.

With that in mind and the observation this project smells all but dead - this seems like a wasted opportunity. I cannot even fork this because it would basically be an 80% rewrite.

Also, what have Siren and Uber to do in a project named hydra-java?

Yes, this is a rant! If you create something, leave it in a prominent place, making it look like a solution to a problem and then just never come back - it will cost other peoples time.

Paxbit

java.lang.IllegalAccessException: Class de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer can not access a member of class ... with modifiers "private"

With the following object :

@Vocab("http://example.com/")
public class Product extends Thing<Product> implements IProduct {

    @JsonInclude(Include.NON_EMPTY)
    private final List<Offer> offers = new ArrayList<>();

    public List<Offer> getOffers() {
        return offers;
    }

    public Product addOffer(Offer offer) {
        getOffers().add(offer);
        return this;
    }

}

hydra-java fails:

com.fasterxml.jackson.databind.JsonMappingException: java.lang.IllegalAccessException: Class de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer can not access a member of class id.co.bippo.product.rs.commerceplug.Offer with modifiers "private" (through reference chain: id.co.bippo.product.rs.commerceplug.Product["offers"]->java.util.ArrayList[0])
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:210)
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:189)
    at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:213)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:105)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21)
    at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:183)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeWithType(BeanSerializerBase.java:525)
    at com.fasterxml.jackson.databind.ser.impl.TypeWrappedSerializer.serialize(TypeWrappedSerializer.java:35)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:114)
    at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:2866)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:2323)
    at id.co.bippo.product.rs.commerceplug.ProductOrServiceImplJsonLdTest.productOrService(ProductOrServiceImplJsonLdTest.java:78)
    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:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.RuntimeException: java.lang.IllegalAccessException: Class de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer can not access a member of class id.co.bippo.product.rs.commerceplug.Offer with modifiers "private"
    at de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer.serializeContext(JacksonHydraSerializer.java:199)
    at de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer.serialize(JacksonHydraSerializer.java:105)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100)
    ... 34 more
Caused by: java.lang.IllegalAccessException: Class de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer can not access a member of class id.co.bippo.product.rs.commerceplug.Offer with modifiers "private"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:101)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:295)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:287)
    at java.lang.reflect.Field.get(Field.java:384)
    at de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer.getTerms(JacksonHydraSerializer.java:251)
    at de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer.serializeContext(JacksonHydraSerializer.java:149)
    ... 36 more

Curiously, the actual cuplrit is not mentioned in the stacktrace above:

public class Offer extends Thing<Offer> {

    private static final long serialVersionUID = 1L;

    private ItemAvailability availability;

    /**
     * The availability of this item—for example {@link ItemAvailability#IN_STOCK}, {@link ItemAvailability#OUT_OF_STOCK},
     * {@link ItemAvailability#PRE_ORDER}, etc.
     * @return
     */
    public ItemAvailability getAvailability() {
        return availability;
    }

    public void setAvailability(ItemAvailability availability) {
        this.availability = availability;
    }

    public Offer withAvailability(ItemAvailability availability) {
        this.availability = availability;
        return this;
    }

}

Workaround: change private ItemAvailability availability; to public ItemAvailability availability;

Spike for hal-forms

FInd out if we can re-use information collected when building the hal response to create hal-forms response.

AffordanceBuilderFactory does not use value of a @RequestParam

I have a controller method with arguments annotated with @RequestParam, like this:

@GetMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView showAsHtml(final @RequestParam("q") String query,
                               final @RequestParam(value = "offset", defaultValue = "0") Long offset,
                               final Locale locale) {
  // do stuff
}

Now I build an Affordance that is an URI template:

AffordanceBuilder.linkTo(AffordanceBuilder.methodOn(MyController.class)
        .showAsHtml(null, null, null))
        .rel("something")
        ...;

The serialized hydra:IriTemplate will look like this:

{
    "@type": "hydra:IriTemplate",
    "hydra:template": "http://localhost:8080/something{?query}",
    "hydra:mapping": [
      {
        "@type": "hydra:IriTemplateMapping",
        "hydra:variable": "query",
        "hydra:required": true,
        "hydra:property": "query"
      }
    ]
  }

So the variable "query" is wrong. It should be "q" as defined by the @RequestParam.

MediaType constant

public static final String APPLICATION_JSONLD_STR = "application/ld+json";
public static final MediaType APPLICATION_JSONLD = MediaType.parseMediaType(APPLICATION_JSONLD_STR);

this should be a public constant somewhere accessible... Or better yet, should propose inclusion of this constant into https://github.com/spring-projects/spring-hateoas

The String is useful for @RequestMapping.

I wonder if should propose the other MediaType constants as well (Collections+JSON, SIREN, JSONAPI) to spring-hateoas?

SpringBoot AutoConfiguration support and Hydra SpringBoot Starter

I've been messing around with Hydra-Java and SpringBoot and have the two working. I have taken the sample project and refactored it into a SpringBoot application:

https://github.com/damnhandy/hydra-springboot

It'd be useful to have a SpringBoot auto configuration module that would provision the correct types using something like an @EnableHydraServer annotation. Taking it a step further, one could also declare which mime types are enabled by specifying them in the annotation value:

@SpringBootApplication
@EnableHydraServer({HYDRA,SIREN,UBER})
public class HydraSampleServiceApplication { ...

I'd be happy to contribute this functionality, but I'm not sure that the core project is the best place for this functionality to live as those not using SpringBoot will not want to deal with those dependencies.

Issue generating links off of request mapping in parent class

I am running into a problem generating links off of routes in a specific scenario. I have a controller method in an abstract parent class that has a signature like this:

    @RequestMapping(method = RequestMethod.GET)
    public HttpEntity<CollectionResource> getCollection(
            @RequestParam(name = "offset") Integer offset,
            @RequestParam(name = "size") Integer size,
            @RequestParam(name = "sort") String sort,
            @RequestParam(name = "q") String q,
            @RequestParam(name = "filter") T filter)

...where T is a generic parameter specified by what is subclassing this parent class. In another unrelated resource, I link to the child class using AffordanceBuilder like so:

        Affordance links = AffordanceBuilder.linkTo(methodOn(
                ChildController.class)
                .getCollection(null, null, null, null, null))
                .withRel("resourcerelation");

What gets generated winds up looking like this:

href: "http://localhost:8080/apinull{?offset,size,sort,q,filter}"

...the obvious issue being that while the base url, context root and uri template all get generated properly, the path is coming through as "null".

Let me know if I can give more specific details about this or create a quick example app that demonstrates it. There is a lot more code around this than what I posted that could possibly have an effect.

java.lang.NullPointerException at de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer.getTerms(JacksonHydraSerializer.java:252)

The NullPointerException should give an explanation what is expected.

The exception is thrown here:

        for (Field field : fields) {
            final Expose fieldExpose = field.getAnnotation(Expose.class);
            if (Enum.class.isAssignableFrom(field.getType())) {
                Map<String, String> map = new LinkedHashMap<String, String>();
                termsMap.put(field.getName(), map);
                if (fieldExpose != null) {
                    map.put(AT_ID, fieldExpose.value());
                }
                map.put(AT_TYPE, AT_VOCAB);
                final Enum value = (Enum)field.get(bean);

                // -------------- EXCEPTION HERE ------------
                final Expose enumValueExpose = getAnnotation(value.getClass().getField(value.name()), Expose.class);


                // TODO redefine actual enum value to exposed on enum value definition
                if (enumValueExpose != null) {
                    termsMap.put(value.toString(), enumValueExpose.value());
                } else {

With following models:

Product.java:

public class Product extends Thing<Product> implements IProduct {

    public static final long serialVersionUID = 1L;

    public OrganizationOrBrand brand;
    public Organization manufacturer;
    public String sku;
    public String barcode;
    public CurrencyUnit priceCurrency;
    public BigDecimal price;
    public DecimalMeasure<Mass> weight;
    public DecimalMeasure<Length> depth;
    public DecimalMeasure<Length> width;
    public DecimalMeasure<Length> height;
    public IColor color;
    public BigDecimal productionCost;
    public InventoryManagement inventoryManagement;
    public InventoryPolicy inventoryPolicy;
    public DecimalMeasure<Quantity> inventoryLevel;
    @Expose("http://www.soluvas.org/commerceplug/1.0#inventoryOnHand")
    public DecimalMeasure<Quantity> inventoryOnHand;
    @JsonInclude(Include.NON_EMPTY)
    public final List<OptionType> optionTypes = new ArrayList<>();
    @JsonInclude(Include.NON_EMPTY)
    public final List<Product> variants = new ArrayList<>();
    protected final List<Offer> offers = new ArrayList<>();
    public String serialNumber;
    @JsonProperty("additionalProperty") @JsonInclude(Include.NON_EMPTY)
    public final List<PropertyValue<?>> additionalProperties = new ArrayList<>();

    @Override
    public OrganizationOrBrand getBrand() {
        return brand;
    }

    @Override
    public void setBrand(OrganizationOrBrand brand) {
        this.brand = brand;
    }

    public Product withBrand(OrganizationOrBrand brand) {
        this.brand = brand;
        return this;
    }

    @Override
    public Organization getManufacturer() {
        return manufacturer;
    }

    @Override
    public void setManufacturer(Organization manufacturer) {
        this.manufacturer = manufacturer;
    }

    public Product withManufacturer(Organization manufacturer) {
        this.manufacturer = manufacturer;
        return this;
    }

    @Override
    public String getSku() {
        return sku;
    }

    @Override
    public void setSku(String sku) {
        this.sku = sku;
    }

    public Product withSku(String sku) {
        this.sku = sku;
        return this;
    }

    @Override
    public String getBarcode() {
        return barcode;
    }

    @Override
    public void setBarcode(String barcode) {
        this.barcode = barcode;
    }

    public Product withBarcode(String barcode) {
        this.barcode = barcode;
        return this;
    }

    @Override
    public CurrencyUnit getPriceCurrency() {
        return priceCurrency;
    }

    @Override
    public void setPriceCurrency(CurrencyUnit currency) {
        this.priceCurrency = currency;
    }

    public Product withPriceCurrency(CurrencyUnit currency) {
        this.priceCurrency = currency;
        return this;
    }

    @Override
    public BigDecimal getPrice() {
        return price;
    }

    @Override
    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public Product withPrice(BigDecimal price) {
        this.price = price;
        return this;
    }

    @Override
    public DecimalMeasure<Mass> getWeight() {
        return weight;
    }

    @Override
    public void setWeight(DecimalMeasure<Mass> weight) {
        this.weight = weight;
    }

    public Product withWeight(DecimalMeasure<Mass> weight) {
        this.weight = weight;
        return this;
    }

    @Override
    public DecimalMeasure<Length> getDepth() {
        return depth;
    }

    @Override
    public void setDepth(DecimalMeasure<Length> depth) {
        this.depth = depth;
    }

    public Product withDepth(DecimalMeasure<Length> depth) {
        this.depth = depth;
        return this;
    }

    @Override
    public DecimalMeasure<Length> getWidth() {
        return width;
    }

    @Override
    public void setWidth(DecimalMeasure<Length> width) {
        this.width = width;
    }

    public Product withWidth(DecimalMeasure<Length> width) {
        this.width = width;
        return this;
    }

    @Override
    public DecimalMeasure<Length> getHeight() {
        return height;
    }

    @Override
    public void setHeight(DecimalMeasure<Length> height) {
        this.height = height;
    }

    public Product withHeight(DecimalMeasure<Length> height) {
        this.height = height;
        return this;
    }

    @Override
    public IColor getColor() {
        return color;
    }

    @Override
    public void setColor(IColor color) {
        this.color = color;
    }

    public Product withColor(IColor color) {
        this.color = color;
        return this;
    }

    @Override
    public BigDecimal getProductionCost() {
        return productionCost;
    }

    @Override
    public void setProductionCost(BigDecimal productionCost) {
        this.productionCost = productionCost;
    }

    public Product withProductionCost(BigDecimal productionCost) {
        this.productionCost = productionCost;
        return this;
    }

    public InventoryManagement getInventoryManagement() {
        return inventoryManagement;
    }

    public void setInventoryManagement(InventoryManagement inventoryManagement) {
        this.inventoryManagement = inventoryManagement;
    }

    public Product withInventoryManagement(InventoryManagement inventoryManagement) {
        this.inventoryManagement = inventoryManagement;
        return this;
    }

    public InventoryPolicy getInventoryPolicy() {
        return inventoryPolicy;
    }

    public void setInventoryPolicy(InventoryPolicy inventoryPolicy) {
        this.inventoryPolicy = inventoryPolicy;
    }

    public Product withInventoryPolicy(InventoryPolicy inventoryPolicy) {
        this.inventoryPolicy = inventoryPolicy;
        return this;
    }

    @Override
    public DecimalMeasure<Quantity> getInventoryLevel() {
        return inventoryLevel;
    }

    @Override
    public void setInventoryLevel(DecimalMeasure<Quantity> inventoryLevel) {
        this.inventoryLevel = inventoryLevel;
    }

    public Product withInventoryLevel(DecimalMeasure<Quantity> inventoryLevel) {
        this.inventoryLevel = inventoryLevel;
        return this;
    }

    @Override
    public DecimalMeasure<Quantity> getInventoryOnHand() {
        return inventoryOnHand;
    }

    @Override
    public void setInventoryOnHand(DecimalMeasure<Quantity> inventoryOnHand) {
        this.inventoryOnHand = inventoryOnHand;
    }

    public Product withInventoryOnHand(DecimalMeasure<Quantity> inventoryOnHand) {
        this.inventoryOnHand = inventoryOnHand;
        return this;
    }

    @Override
    public List<OptionType> getOptionTypes() {
        return optionTypes;
    }

    public Product addOptionType(OptionType optionType) {
        getOptionTypes().add(optionType);
        return this;
    }

    @Override
    public List<Product> getVariants() {
        return variants;
    }

    public Product addVariant(Product variant) {
        getVariants().add(variant);
        return this;
    }

    @JsonInclude(Include.NON_EMPTY)
    public List<Offer> getOffers() {
        return offers;
    }

    public Product addOffer(Offer offer) {
        getOffers().add(offer);
        return this;
    }

    @Override
    public String getSerialNumber() {
        return serialNumber;
    }

    @Override
    public void setSerialNumber(String serialNumber) {
        this.serialNumber = serialNumber;
    }

    public Product withSerialNumber(String serialNumber) {
        this.serialNumber = serialNumber;
        return this;
    }

    @Override
    public List<PropertyValue<?>> getAdditionalProperties() {
        return additionalProperties;
    }

    public Product withAdditionalProperty(PropertyValue<?> propertyValue) {
        getAdditionalProperties().add(propertyValue);
        return this;
    }

}

Thing.java:

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"id", "name", "description", "image", "url",
    "additionalType", "alternateName", "potentialAction", "sameAs"})
@SuppressWarnings("unchecked")
public class Thing<C extends IThing> extends ResourceSupport 
    implements IThing, Serializable {

    public static final long serialVersionUID = 1L;

    public String id;
    @JsonProperty("additionalType") @JsonInclude(Include.NON_EMPTY)
    public final List<String> additionalTypes = new ArrayList<>();
    public String alternateName;
    public String description;
    public ImageObject image;
    public String name;
    public Action potentialAction;
    public String sameAs;
    public String url;
    @JsonIgnore
    public final Map<String, Object> customProperties = new LinkedHashMap<>();

    @Override
    @JsonProperty("id")
    public String getThingId() {
        return id;
    }

    @Override
    public void setThingId(String id) {
        this.id = id;
    }

    public C withThingId(String id) {
        this.id = id;
        return (C) this;
    }

    @Override
    public List<String> getAdditionalTypes() {
        return additionalTypes;
    }

    public C addAdditionalType(String additionalType) {
        getAdditionalTypes().add(additionalType);
        return (C) this;
    }

    @Override
    public String getAlternateName() {
        return alternateName;
    }

    public void setAlternateName(String alternateName) {
        this.alternateName = alternateName;
    }

    @Override
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public C withDescription(String description) {
        this.description = description;
        return (C) this;
    }

    @Override
    public ImageObject getImage() {
        return image;
    }

    public void setImage(ImageObject image) {
        this.image = image;
    }

    @Override
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public C withName(String name) {
        this.name = name;
        return (C) this;
    }

    @Override
    public Action getPotentialAction() {
        return potentialAction;
    }

    public void setPotentialAction(Action potentialAction) {
        this.potentialAction = potentialAction;
    }

    @Override
    public String getSameAs() {
        return sameAs;
    }

    public void setSameAs(String sameAs) {
        this.sameAs = sameAs;
    }

    @Override
    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @JsonAnyGetter
    public Map<String, Object> getCustomProperties() {
        return this.customProperties;
    }

    @JsonAnySetter
    public void setCustomProperty(String name, Object value) {
        this.customProperties.put(name, value);
    }

    public C withCustomProperty(String name, Object value) {
        this.customProperties.put(name, value);
        return (C) this;
    }

}

Error:

com.fasterxml.jackson.databind.JsonMappingException: java.lang.NullPointerException
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:125)
    at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:2866)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:2323)
    at id.co.bippo.product.rs.commerceplug.ProductOrServiceImplJsonLdTest.productOrService(ProductOrServiceImplJsonLdTest.java:45)
    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:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
    at de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer.serializeContext(JacksonHydraSerializer.java:199)
    at de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer.serialize(JacksonHydraSerializer.java:105)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:114)
    ... 27 more
Caused by: java.lang.NullPointerException
    at de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer.getTerms(JacksonHydraSerializer.java:252)
    at de.escalon.hypermedia.hydra.serialize.JacksonHydraSerializer.serializeContext(JacksonHydraSerializer.java:149)
    ... 29 more

Issue with traverson

While using traveson getting below error
java.lang.IllegalStateException: Did not find LinkDiscoverer supporting media type application/vnd.siren+json;charset=UTF-8!

I am using below configuration

@Bean
  public RestOperations restOperations() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setRequestFactory(new HttpComponentsAsyncClientHttpRequestFactory());
    restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor(user, password));
    return restTemplate;
  }

  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(sirenMessageConverter());
  }


  @Bean
  public SirenMessageConverter sirenMessageConverter() {
    SirenMessageConverter sirenMessageConverter = new SirenMessageConverter();
    sirenMessageConverter.setSupportedMediaTypes(Collections.singletonList(SIREN_JSON));
    return sirenMessageConverter;
  }

and calling it like

Traverson traverson = new Traverson(URI.create(baseUrl+"/api.json"), SIREN_JSON);
traverson.setRestOperations(restOperations);
ResponseEntity<Entity>  entity = traverson.follow("child").toEntity(Entity.class);

What am I doing wrong, or this extension doesn't add mediaType support for siren with traverson.
Would be nice if you can build an AutoConfigurationClass

I believe to make it work, we need to add the entry in PluginRegistry with MediaType.SIREN_JSON

AffordanceBuilder GET methods not listed

Hello,

I've tried to reference some hydra:operation in my responses, but whatever the Annotations I put on the controller, I can't show them in the operations list.

The Controller Interface :

@Api(value = "hydra", description = "the hydra API")
public interface HydraApi {

    @ApiOperation(value = "", notes = "", response = Void.class, tags={  })
    @ApiResponses(value = { 
        @ApiResponse(code = 200, message = "Successfully added device", response = Void.class) })
    
    @RequestMapping(value = "/hydra/device",
        produces = { "application/ld+json" }, 
        method = RequestMethod.POST)
    ResponseEntity<Object> add(@ApiParam(value = "" ,required=true )  @Valid @RequestBody Device body);


    @ApiOperation(value = "", notes = "", response = Void.class, tags={  })
    @ApiResponses(value = { 
        @ApiResponse(code = 200, message = "Successfully deleted device", response = Void.class) })
    
    @RequestMapping(value = "/hydra/device",
        produces = { "application/ld+json" }, 
        method = RequestMethod.DELETE)
    ResponseEntity<Object> delete(@ApiParam(value = "" ,required=true )  @Valid @RequestBody Device body);


    @ApiOperation(value = "", notes = "", response = DeviceData.class, tags={  })
    @ApiResponses(value = { 
        @ApiResponse(code = 200, message = "Successfully read device data", response = DeviceData.class) })
    
    @RequestMapping(value = "/hydra/device/read/{maker}/{model}/{serial}",
        produces = { "application/ld+json" }, 
        method = RequestMethod.GET)
    ResponseEntity<Object> read(@ApiParam(value = "Maker of the device",required=true ) @PathVariable("maker") String maker,
                                @ApiParam(value = "Model of the device",required=true ) @PathVariable("model") String model,
                                @ApiParam(value = "Serial of the device",required=true ) @PathVariable("serial") String serial);


    @ApiOperation(value = "", notes = "", response = EntryPoint.class, tags={  })
    @ApiResponses(value = { 
        @ApiResponse(code = 200, message = "The API endpoints", response = EntryPoint.class) })
    
    @RequestMapping(value = "/hydra",
        produces = { "application/ld+json" }, 
        method = RequestMethod.GET)
    ResponseEntity<Object> rootEntryPoint();

}

The Resource builder :

    public ResponseEntity<Object> process() {
        ResponseEntity ret;

        try {
            Resource<EntryPoint> entryPointResource =
                    new Resource<>(new EntryPoint());

            entryPointResource.add(
                    linkTo(methodOn(HydraApi.class).add(new Device()))
                            .and(linkTo(methodOn(HydraApi.class).delete(new Device())))
                            .and(linkTo(methodOn(HydraApi.class).read("a", "b", "c")))
                            .withSelfRel()
            );
            ret = new ResponseEntity<Resource>(
                    entryPointResource,
                    HttpStatus.OK
            );
        } catch (Exception e) {
            ret = resolveException(e);
        }
        return new ResponseEntity<>(ret.getBody(), ret.getStatusCode());
    }

The response of the Resource builder :

{
  "@context": {
    "@vocab": "http://schema.org/"
  },
  "@type": "EntryPoint",
  "@id": "http://localhost:8080/hydra/device",
  "hydra:operation": [
    {
      "hydra:method": "POST",
      "hydra:expects": {
        "@type": "Device",
        "hydra:supportedProperty": [
          {
            "hydra:property": "serial"
          },
          {
            "hydra:property": "maker"
          },
          {
            "hydra:property": "model"
          }
        ]
      }
    },
    {
      "hydra:method": "DELETE",
      "hydra:expects": {
        "@type": "Device",
        "hydra:supportedProperty": [
          {
            "hydra:property": "serial"
          },
          {
            "hydra:property": "maker"
          },
          {
            "hydra:property": "model"
          }
        ]
      }
    }
  ]
}

Thanks in advance for the answer !

Using the Affordance Builder with a null HttpServletRequest

When testing code that uses the AffordanceBuilder.java and not using a library like Mockito or MockMvc, since there is no HttpServlet Context, the HttpServletRequest object is null,

  static UriComponentsBuilder getBuilder() {

        HttpServletRequest request = getCurrentRequest();
        ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromServletMapping(request);

        String forwardedSsl = request.getHeader("X-Forwarded-Ssl");

inserting this line:

  static UriComponentsBuilder getBuilder() {
        if (RequestContextHolder.getRequestAttributes() == null) {
            			return UriComponentsBuilder.fromPath("");
            		}

        HttpServletRequest request = getCurrentRequest();
        ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromServletMapping(request);

        String forwardedSsl = request.getHeader("X-Forwarded-Ssl");

Makes it work, as found here : spring-projects/spring-hateoas#592

Consider moving this project to an organization, possibly new name

First of this, this is a fantastic project. I came here looking for Hydra support, and found Über, Siren, and HAL as well. I think this project has legs as it's very powerful.

I'd like to suggest creating a top-level organization for this project. This would make it simpler to include things like example apps, which may not leverage the same dependency set as the core project. For example, a Spring Boot example would be useful, but likely isn't a good fit for inclusion in the core project.

But this leads to another suggestion: given this project's vast support for other hypermedia formats beyond JSON-LD and Hydra, is hydra-java a reasonable name going forward? This project seems to be shaping up to be a general-purpose Hypermedia framework, of which JSON-LD plus Hydra is one such option. Thoughts?

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.