Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot make converter from byte[] to String #693

Closed
magnusar opened this issue Sep 26, 2014 · 24 comments
Closed

Cannot make converter from byte[] to String #693

magnusar opened this issue Sep 26, 2014 · 24 comments
Labels
Milestone

Comments

@magnusar
Copy link

The examples for how to use an OverrideConverter for Calendar objects, for example described here #359 works fine for us.

But I'm unable to make a converter work for the type byte[] that outputs it as a String. How can this be achieved? The following does not work:

OverrideConverter converter = new OverrideConverter();
converter.add("array[byte]", jsonString);
ModelConverters.addConverter(converter, true);

Our property looks like this:
@ApiModelProperty(value = "base64 encoded string", notes = "base64 string", required = true)
private byte[] myBytes;

We are using com.wordnik:swagger-jaxrs_2.11:1.3.10 in a Dropwizard project.

@webron
Copy link
Contributor

webron commented Sep 26, 2014

Instead of using a converter, have you tried the following?

@ApiModelProperty(value = "base64 encoded string", dataType="string", notes = "base64 string", required = true)
private byte[] myBytes;

I'm not entirely sure it'll work with string, but if not, you can also try String or java.lang.String.

@magnusar
Copy link
Author

Yes I've already tried that. It doesn't work. It produces a Scala match error "scala.MatchError: string (of class java.lang.String)"

(Using just byte in combination with dataType="string" works fine and the output is a string. It's the byte[] that I can't make work.)

@webron
Copy link
Contributor

webron commented Sep 26, 2014

You've tried all 3 variants?
Also, not that it should matter, can you also try changing your dependency to swagger-jersey-jaxrs instead?

@webron
Copy link
Contributor

webron commented Sep 26, 2014

Hmm, it looks like this is related to #334 unfortunately.
I'm not sure you can assign a converter to an array, but @fehguy will have to comment on that.

@magnusar
Copy link
Author

Sorry, what are the three variants? Yeah I can try changing the dependency.

@webron
Copy link
Contributor

webron commented Sep 26, 2014

Well, you can try string, String, or java.lang.String.

@fehguy
Copy link
Contributor

fehguy commented Sep 26, 2014

I don't believe you can override datatypes in model properties, period.

@fehguy
Copy link
Contributor

fehguy commented Sep 26, 2014

Yes, you can add the annotations, but I don't believe they're honored. I'd suggest checking the tests.

Per @webron's comment below, I was mistaken.

@webron
Copy link
Contributor

webron commented Sep 27, 2014

Just tested it and it works fine. I've used @ApiModelProperty(dataType="string") on a getter of a long field and the specification came out as string.

@magnusar - if it doesn't work for you, could you please produce a test case I can check locally?

@magnusar
Copy link
Author

@webron && @fehguy : I'm not surprised that the annotation worked for long -> String, since it worked for me with byte -> String. The problem is the array primitive. So if you can make anything primitive[] working (preferably byte[] since that is my case) that would probably solve it.

If I end up having to patch the code myself, do you please have any pointers as to how I would go about making a converter work for arrays of Java primitives? (I'm totally new to Scala...)

Thanx for the feeback.

@webron
Copy link
Contributor

webron commented Sep 28, 2014

Okay, I did some further testing. The problem is not related with primitive arrays but rather with arrays or anything that translates to an array. The type can be a primitive or a class, and the array could be a java array or the collections we parse as arrays (List, Set...). And this is a bug the way I see it.

@fehguy - could you look into that please?

@fehguy
Copy link
Contributor

fehguy commented Sep 28, 2014

it is impossible to support all overrides in this fashion. It's a string, and to read the annotation, we're instantiating the class. So "List[String]" is not only invalid syntax for java, but impossible to instantiate because List isn't a concrete class.

I suggest we document the behavior, add support for overrides in the property parsing, and start using concrete classes for overrides rather than string representations.

@webron
Copy link
Contributor

webron commented Sep 29, 2014

With swagger-core 1.5 I don't think it's relevant anymore, but I'm not sure follow everything you say here.
I agree with the usage of concrete classes instead of a string (though it would be a problem with collections). But what is the actual problem with replacing a value type of array with another one?
Just to make sure we're on the same page, I'm referring to this:

@ApiModelProperty(dataType="string")
private byte[] myBytes;

vs

@ApiModelProperty(dataType="string")
private long date;

The first sample doesn't work, the second works fine.

@magnusar
Copy link
Author

As an input to the discussion, when I look at the response body where we also have a byte[] it looks like this in the Swagger UI if I click the Model link:

MyClass {
anotherByteArray (array[byte]): base64 encoded byte array
}

So "array[byte]" is used as syntax at least in the output. I don't know if that's relevant but that's why I tried "converter.add("array[byte]", jsonString);" as stated in the issue.

@magnusar
Copy link
Author

We absolutely need to make the byte[] => string conversion work. (In the worst case I will have to try and patch the code myself or we have to choose some other framwork.) Do you think you guys could add a fix for this in the near future?

@webron
Copy link
Contributor

webron commented Sep 29, 2014

@magnusar - there is a workaround but that would require you to duplicate your model and may add a few additional annotations for the documentation. It may be enough for you for now.

@magnusar
Copy link
Author

@webron could you please give me an example of that workaround and what extra annotations I should add?

@webron
Copy link
Contributor

webron commented Sep 29, 2014

It's a bit difficult since I don't know how you use your model (as a body parameter, response type..).

For starters, you'd have to create a copy of the class and replace the byte[] field with a String field.

@magnusar
Copy link
Author

Ok, here's a simplified version of the model:

MyView.java:

@DaTa
@AllArgsConstructor
@NoArgsConstructor
@apimodel(value = "Bla bla bla")
public class MyView {

@ApiModelProperty(value = "a name", required = true)
private String name;

@ApiModelProperty(value = "some text", dataType="", notes = "base64 string", required = true)
private byte[] byteArray;
}

And then we use it like this:

@post
@path("/someservice")
@ApiOperation(value = "bla, bla",
notes = "bla bla",
response = MyView.class)
public MyView doRequest(@ApiParam(value = "Parameters for ...", required = true) InputObject inputObject) {

return getNewMyViewInstance(inputObject);

}

@webron
Copy link
Contributor

webron commented Sep 29, 2014

Okay, so you'd have something like this:

@ApiModel(value = "MyView")
public class MySwaggerView {

@ApiModelProperty(value = "a name", required = true)
private String name;

@ApiModelProperty(value = "some text", notes = "base64 string", required = true)
private String byteArray;
}

And:

@POST
@Path("/someservice")
@ApiOperation(value = "bla, bla",
notes = "bla bla",
response = MySwaggerView.class)
public MyView doRequest(@ApiParam(value = "Parameters for ...", required = true) InputObject inputObject) {

return getNewMyViewInstance(inputObject);

}

(I'm ignoring the fact that in the sample there are only private fields with no setters)

@magnusar
Copy link
Author

Yeah, that works. Thanks! (The setters are generated automatically by the Lombok annotation @DaTa.)

I'm not sure this duplication of model classes will be acceptable as a solution but perhaps we can use it temporarily. Do you know if we can expect a fix for this issue in a future snapshot release of Swagger?

@webron
Copy link
Contributor

webron commented Sep 29, 2014

As said it's a workaround. I can't comment as to if or when a different solution will be available.

@fehguy fehguy added the Feature label Dec 20, 2014
@fehguy fehguy added this to the v1.3.12 milestone Dec 20, 2014
@fehguy
Copy link
Contributor

fehguy commented Dec 21, 2014

OK I've dug into this--you cannot change a model property with an override converter from an array to a simple type like string. I understand where it may be desirable but I think this is more of a design challenge in the API than a configuration in swagger.

You can do this:

@ApiModelProperty(dataType="string")
var myBytes: Array[Byte] = _

but the model will be this:

  "properties": {
    "myBytes": {
      "type": "array",
      "items": {
        "type": "string",
        "format": "byte"
      }
    }
  }

I have fixed the error message to not be so opaque, though, as you first reported:

2f2caca

@fehguy fehguy closed this as completed Dec 21, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants