Olingo (OData 4) + JPA: how to redefine the Metadata?

286 Views Asked by At

In Odata2 there is a possibility to redefine the metamodel. The following page describes the process: https://olingo.apache.org/doc/odata2/tutorials/jparedefinemetadata.html

I haven't found a way to do such conversion with OData v4/Olingo/JPA. I am using the SAP implementation olingo-jpa-processor-v4 which exists at https://github.com/SAP/olingo-jpa-processor-v4

What I am looking for is to change the external name of some classes or attributes.

I have tried to use the JPAEdmNameBuilder class but the methods of that class do not have enough information to make the changes of the attributes according to the entity from which they come. These methods only receive the name of the attribute (and not the name of the entity) so it would not be possible to selectively rename an attribute that appears in two entities.

Any suggestions on how to do that conversion?

Thank you very much

Note: there is a related question at: Olingo (OData 4): how set translation of EntitySet (Entity) names? but it is quite old and very specific. My hope is that a functionality similar to what exists in Odata2 would have been implemented during this time.

1

There are 1 best solutions below

0
On

This is quite a old thread, but I ran into the same issue, and came across a solution hence posting it here.

So while creating JPAODataSessionContextAccess you can call setEdmNameBuilder function to set the EdmBuilder.

If nothing is passed in line 165 of JPAODataServiceContext a new instance of JPADefaultEdmNameBuilder is created and set.

JPADefaultEdmNameBuilder in the current code is marked as final, so you can't subclass it, but you can build define a class that implements JPAEdmNameBuilder, that has your custom logic and pass set it in JPAODataSessionContextAccess

For reference the code for setting your custom class will be something like

   @Bean
    public JPAODataSessionContextAccess sessionContext(@Autowired final EntityManagerFactory emf) throws ODataException {

        return JPAODataServiceContext.with()
                .setPUnit(punit)
                .setEntityManagerFactory(emf)
                .setTypePackage(rootPackages)
                .setRequestMappingPath("true/v1")
                .setEdmNameBuilder(new CustomJPADefaultEdmNameBuilder("MyNameSpace"))
                .build();
    }

and the implementation of CustomJPADefaultEdmNameBuilder can be like the following

public class CustomJPADefaultEdmNameBuilder implements JPAEdmNameBuilder {

    private final String namespace;

    public static String firstToUpper(String jpaAttributeName) {
        return Character.toUpperCase(jpaAttributeName.charAt(0)) + jpaAttributeName.substring(1);
    }

    public CustomJPADefaultEdmNameBuilder(@Nonnull String namespace) {
        this.namespace = (String) Objects.requireNonNull(namespace);
    }

    public final String buildComplexTypeName(EmbeddableType<?> jpaEmbeddedType) {
        return jpaEmbeddedType.getJavaType().getSimpleName();
    }

    public String buildContainerName() {
        StringBuilder containerName = new StringBuilder();
        String[] elements = this.namespace.split("\\.");
        String[] var3 = elements;
        int var4 = elements.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String element = var3[var5];
            containerName.append(firstToUpper(element));
        }

        containerName.append("Container");
        return containerName.toString();
    }

    public final String buildEntitySetName(String entityTypeName) {
        return entityTypeName.charAt(entityTypeName.length() - 1) == 'y' && entityTypeName.charAt(entityTypeName.length() - 2) != 'a' && entityTypeName.charAt(entityTypeName.length() - 2) != 'e' && entityTypeName.charAt(entityTypeName.length() - 2) != 'i' && entityTypeName.charAt(entityTypeName.length() - 2) != 'o' && entityTypeName.charAt(entityTypeName.length() - 2) != 'u' ? entityTypeName.substring(0, entityTypeName.length() - 1) + "ie" + "s" : entityTypeName + "s";
    }

    public String buildEntityTypeName(EntityType<?> jpaEntityType) {
        return jpaEntityType.getName();
    }

    public final String getNamespace() {
        return this.namespace;
    }

    public final String buildNaviPropertyName(Attribute<?, ?> jpaAttribute) {
        return this.buildPropertyName(jpaAttribute.getName());
    }

    public final String buildPropertyName(String jpaAttributeName) {
        return firstToUpper(jpaAttributeName);
    }

    public final String buildOperationName(String internalOperationName) {
        return firstToUpper(internalOperationName);
    }

    public final String buildEnumerationTypeName(Class<? extends Enum<?>> javaEnum) {
        return javaEnum.getSimpleName();
    }
}