gjrwebber / spring-data-gremlin

Spring data gremlin makes it easier to implement Graph based repositories. This module extends Spring Data to allow support for potentially any Graph database that implements the Tinkerpop Blueprints 2.x API.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

I don't know how to save a object property of Vertex

buiminhhuy opened this issue · comments

example:
@vertex
public class OAuth2AuthenticationAccessToken extends AbstractDomainEntity {
private static final long serialVersionUID = -3919074495651349876L;

@Index
private String tokenId;

@Property
private OAuth2AccessToken oAuth2AccessToken;

private String authenticationId;

@Index
private String userName;

@Index
private String clientId;

@Property
private OAuth2Authentication authentication;

@Index
private String refreshToken;
//contructor get set

}

Note: OAuth2AccessToken, OAuth2Authentication are two interface of Spring FrameWork. They will instance object when runtime. I don't know how to save them in OrientDB. in them may be have some another Class. May be refer below image.
runtime

Hi Gjwebber,
Above problem, I think you should be add a description to annotation @Property (type = String.class) or your mind. when saving this Properties you can check and convert object to Type in the @Property annotation.

Help me resolve this problem. Because I am processing it in my project.

@buiminhhuy, let me know how you think it should be saved? As a Serialized Object? Which means it has to implement Serializable. How can we save an Object that is not an "entity" or vertex or @Embedded object?

Yes I mean the both two your questions:

  • You can save it As a Serialized Object or String (json).
  • How can we save an Object that is not an "entity" or vertex or @Embedded object?

Hi @gjrwebber , You have any update for this problem. I think the problem will necessary for your project. When a vertex or Edge have properties type are binary, json object, serialized object,...

@gjrwebber, Help me :D

@buiminhhuy I am working on #21 at the moment. If you want an issue resolved, how about contributing? Fork the repo, branch it, fix it and merge request it :)

Ok @gjrwebber, I am very happy if I am become contributor for your project. I will try to resolve.

@buiminhhuy I have some time now to look at this one. Are you working on it?

No, I am busy for my company project.

ALright, I'll look at it.

I should also note that if you want to ignore the property you can still use transient keyword or @ignore.

ok, Thanks You.

I got a error:
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class org.springframework.security.oauth2.provider.OAuth2Authentication]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: java.io.StringReader@5df99cba; line: 1, column: 2]

image

The error occurred because the Object OAuth2Authentication of Spring Framework no constructor suitable.

To resolve the bug, you can supply me how to add a converter to this. Or you can save Object under type binary data.

Before I have implemented for Neo4j by Converter but on your framework, I don't know. You can ref http://stackoverflow.com/questions/28399712/neo4j-tokenstore-spring-oauth2/29910299#29910299 (this link I implement on Neo4j)

You'll have to add a mixin (new) as described here to the @Property annotation.

Something like @Property(jsonMixin = OAuth2AuthenticationMixin.class) where OAuth2AuthenticationMixin will have to be written by you.

Thanks for quick response.

Hi @gjrwebber
I added OAuth2AuthenticationMixin.class to OAuth2AuthenticationAccessToken.

public abstract class OAuth2AuthenticationMixin {
    OAuth2AuthenticationMixin(@JsonProperty("oauth2Request") OAuth2Request storedRequest, @JsonProperty("userAuthentication") Authentication userAuthentication) {}
    @JsonProperty("oauth2Request") abstract OAuth2Request getOAuth2Request(); // rename property
    @JsonProperty("userAuthentication") abstract Authentication getUserAuthentication(); // rename property

}

It seem work ok, but I again get a bug with OAuth2Request, mixin Json as below:

GremlinSchema:236] Could not load property GremlinProperty{name='authentication', accessor=org.springframework.data.gremlin.schema.property.accessor.GremlinJSONFieldPropertyAccessor@76dccb0c, type=class java.lang.String} of <mypackage>.OAuth2AuthenticationAccessToken@abd6d973
java.lang.IllegalStateException: Can not construct instance of org.springframework.security.core.GrantedAuthority, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
 at [Source: java.io.StringReader@677a625a; line: 1, column: 192] (through reference chain: org.springframework.security.oauth2.provider.OAuth2Request["authorities"])

I need implement to deserialize in
@Property
private OAuth2AccessToken oAuth2AccessToken;

Set<String> scope = mapper.readValue(jsonNode.get("scope"), new TypeReference<HashSet<String>>() {});

or for authorities above, because default json parse wrong syntax.
I thinks, I must be add converter to convert as my expectation, before converter as below

public class StringToOAuth2AuthenticationConverter implements Converter<String, OAuth2Authentication> {

    @Override
    public OAuth2Authentication convert(final String source) {
        // some code that takes a String and returns an object of your type
        OAuth2Authentication oAuth2Authentication = null;
        try {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode  rootNode = mapper.readTree(source);
            OAuth2Request oAuth2Request = getOAuth2Request(rootNode.get("oauth2Request"), mapper);
            JsonNode userAuthentication = rootNode.get("userAuthentication");
            JsonNode principal = userAuthentication.get("principal");
            UserAccount userAccount = mapper.readValue(principal.get("userAccount"), UserAccount.class);
            BBUserDetails userDetails = new BBUserDetails(userAccount);
            List<Map<String, String>> authorities = mapper.readValue(userAuthentication.get("authorities"), new TypeReference<List<Map<String, String>>>() {});
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, getAuthorities(authorities));
            oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return oAuth2Authentication;
    }

    private OAuth2Request getOAuth2Request(final JsonNode jsonNode, ObjectMapper mapper) throws JsonParseException, JsonMappingException, IOException{
        Map<String, String> requestParameters = mapper.readValue(jsonNode.get("requestParameters"),new TypeReference<Map<String, String>>() {});
        String clientId = jsonNode.get("clientId").getTextValue();
        List<Map<String, String>> authorities = mapper.readValue(jsonNode.get("authorities"), new TypeReference<List<Map<String, String>>>() {});
        Set<String> scope = mapper.readValue(jsonNode.get("scope"), new TypeReference<HashSet<String>>() {});
        Set<String> resourceIds =   mapper.readValue(jsonNode.get("resourceIds"), new TypeReference<HashSet<String>>() {});
        return new OAuth2Request(requestParameters, clientId, getAuthorities(authorities) , true, scope, resourceIds, null, null, null);
    }

    private Collection<? extends GrantedAuthority> getAuthorities(
            List<Map<String, String>> authorities) {
        List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(authorities.size());
        for (Map<String, String> authority : authorities) {
            grantedAuthorities.add(new SimpleGrantedAuthority(authority.get("authority")));
        }
        return grantedAuthorities;
    }

}

I completed this. as below code:

public abstract class OAuth2AuthenticationMixin {
    @JsonCreator
    OAuth2AuthenticationMixin(@JsonProperty("oauth2Request") OAuth2Request storedRequest, 
                                @JsonProperty("userAuthentication") Authentication userAuthentication) {}

    @JsonDeserialize(using=CustomOAuth2RequestDeserializer.class) abstract OAuth2Request getOAuth2Request(); // rename property
    @JsonDeserialize(using=CustomAuthenticationDeserializer.class) abstract Authentication getUserAuthentication(); // rename property
    @JsonDeserialize(using=CustomAuthorityDeserializer.class) abstract Collection<? extends GrantedAuthority> getAuthorities(); // rename property
    @JsonIgnore abstract Object getPrincipal();
    @JsonIgnore abstract Object getCredentials();
    @JsonIgnore abstract boolean isClientOnly();
    @JsonIgnore abstract String getName();
}