Mulgard
Mulgard

Reputation: 10589

Graphql Tools: Map entity type to graphql type

I'm using graphql java tools in my spring application. I have an entity like this:

@Entity
data class Image(
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        @Column(nullable = false)
        val id: Long = 0
) {
    @Lob
    @Column(nullable = false)
    var image: Blob? = null
}

And in the GraphQL schema I want to have a different type:

type Image {
    id: ID!
    image: String!
}   

Starting this won't work, of course, because of a schema parsing exception. So I thought it must be possible to put something in between the schema parsing to implement a mapping from Blob to String.

Is this somehow possible here?

@Bean
fun schemaParserDictionary(): SchemaParserDictionary {
    return SchemaParserDictionary()
}

EDIT

Sorry, it won't give a schema parsing exception. It will simply put the bytes into a string. But I can't use that string then to create the image.

Clarification

Sorry, I guess I was not clear enough with my question. I don't need to know how to transform a blob into a string. There are very easy solutions for that. For example I can use a simple API function to transform byte code into base64:

val base64 = Base64.getEncoder().encodeToString(byteCode)

What I tried to ask was how I can "tell" graphql schema parser to use that "custom" transformation for a specific field. So when my entity object has the field image with datatype blob graphql is automatically transforming this to a string. But the string does not contain the content that I need. So I want to use a custom parsing / mapping / transformation / whatever for that particularly field. Of course, I could also easily get around this by introducing another field which I do not store in the database:

@Entity
data class Image(
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        @Column(nullable = false)
        val id: Long = 0
) {
    @Lob
    @Column(nullable = false)
    var image: Blob? = null

    @Transient
    var base64: String = ""
}

but which I make queryable through the graphql api:

type Image {
    id: ID!
    image: String!
    base64: String!
}

type Images {
    images: [Image!]!
    totalCount: Int!
}

type Query {
    getImages: Images!
}

And set it in my controller:

private fun getImages(): Images {
    var images: List<Image> = repository.findTop1000()

    images.forEach {
        it.base64 = Base64.getEncoder().encodeToString(it.image)

        queue.offer(it)
    }
}

But it would be cleaner if I could tell the graphql schema parser to do that.

Upvotes: 1

Views: 4105

Answers (3)

etienne-sf
etienne-sf

Reputation: 164

Why don't you use a Custom Scalar? It directly answers your starting question:

So I thought it must be possible to put something in between the schema parsing to implement a mapping from Blob to String.

Is this somehow possible here?

You GraphQL schema would be:

scalar ImageBlob
type Image {
    id: ID!
    image: ImageBlob!
} 

Then, in the Custom Scalar implementation, you provide the transformation of a Blob from and to a String.

Upvotes: 1

AllirionX
AllirionX

Reputation: 1143

Kushal's answer provides the snippets to convert a Blob to a String. To use this conversion, it is good practice to use DTO.

To do so, transform your graphql schema to:

type ImageDTO {
    id: ID!
    image: String!
} 

And create a DTO class ImageDTO:

public class ImageDTO {
    private Image entity;

    //Constructor
    public ImageDTO(Image image) {
         this.entity=image;
    }

    //Getters
    public Long getId() {
        return entity.getId();
    }

    public String getImage() {
        //convert the entity image and return it as String
        return Base64.getEncoder().encodeToString(entity.getImage());
    }
}

Separating the DTO from the entity grants you a finer control on the data transferred.

Upvotes: 4

Kushal Srivastava
Kushal Srivastava

Reputation: 45

Let's check it from the beginning. We know that BLOB is an acronym for Binary Large Object used for storing Byte & byte data that exceeds the regular size allowed by the specific datatypes. Converting a BLOB into a string in memory can sometimes cause OutOfMemoryException if the BLOB data is too large.

But still if you would like to convert BLOB to string here is the code-piece you can try this:

String s = "";
InputStream inStream = b.getBinaryStream();
//b is your BLOB
InputStreamReader inStreamReader = new InputStreamReader(inStream);
BufferedReader reader = new BufferedReader(inStreamReader );
StringBuffer buf = new StringBuffer();
while(s = reader.readLine())
{
   buf.append(s);
}

there are several more approach you can take one of them is to

ByteArrayOutputStream baos = new ByteAttayOutputStream();
byte[] buf = new byte[1024];
InputStream in = blob.getBinaryStream();
int n = 0;
while ((n=in.read(buf))>=0)
{
   baos.write(buf, 0, n);
}
in.close();
byte[] bytes = baos.toByteArray();
String blobString = new String(bytes); 

I would appreciate any further queries from your side.

Upvotes: 2

Related Questions