Calling parseFrom() method for generic protobuffer class in java - java

I'm calling an api to get the an input stream and then call static method parseFrom(inputstream) to convert it to the protobuffclass.
If I do it with a specific class it works:
public CustomerDTOOuterClass.CustomerDTO GetCustomer()
{
CustomerDTOOuterClass.CustomerDTO customer = null;
try
{
URL url = new URL("https://localhost:44302/Api/customer/1?");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-Type", "application/x-protobuf");
conn.connect();
InputStream is = conn.getInputStream();
CustomerDTOOuterClass.CustomerDTO customer =
CustomerDTOOuterClass.CustomerDTO.parseFrom(is);
conn.disconnect();
}
catch(Exception ex)
{
System.out.println("[ "+ex.getMessage()+" ]");
}
return customer;
}
but if I change it to generic type it fails because T doesn't have the method parseFrom, is there any interface I could implement in T so I can call the parseFrom method?
public T GetObject()
{
T object = null;
try
{
URL url = new URL("https://localhost:44302/Api/customer/1?");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-Type", "application/x-protobuf");
conn.connect();
InputStream is = conn.getInputStream();
T object = T.parseFrom(is);
conn.disconnect();
}
catch(Exception ex)
{
System.out.println("[ "+ex.getMessage()+" ]");
}
return object;
}
this is the error I get:
Error:(68, 27) error: cannot find symbol method parseFrom(InputStream)

Every generated protobuf type contains a static member called PARSER which is an implementation of the com.google.protobuf.Parser<T> interface. Your getObject method simply needs to take a Parser<T> as a parameter. So then you'd call it like:
Foo foo = getObject(Foo.PARSER);

If you want to do this for T, it's easier and more natural to pass the Class<T> (i.e. the class of the Proto type) into the constructor of your class, and then obtain the Parser from that like this:
public class Thing<T extends Message> {
final Parser<T> parser;
Thing(Class<T> cls) {
parser = (Parser<T>) cls.getMethod("parser").invoke(null);
}
T deserialize(byte[] bytes) {
parser.parseFrom(bytes); // try/catch etc
}
}

To expand on Kenton Varda's answer:
First I'd refactor your method into separate methods for getting the input stream and parsing it. Only the latter has any reason to be generic.
public InputStream getInputStream() {
// get it
}
Now you intend to parse the input stream and build a POJO from the protobuf. It's reasonable IMO to expect that at this point your code must be aware of what type of object you're going to get, because otherwise how would you do something intelligent with it next? E.g.
InputStream is = getInputStream();
Object o = parseGenericInputStream(is);
doSomethingWithParsedObject(o); // how to do this if you don't know o's type?
You reasonably must know o's type once you've parsed it (and therefore before you parse it), otherwise you can't do anything meaningful with it that I can think of.
So... again with credit to Kenton Varda:
public void doStuff() {
...
InputStream is = getInputStream();
MyProtobufClass pojo = parseGenericInputStream(MyProtobufClass.PARSER, is);
doSomethingWithParsedObject(pojo);
...
}
private <T> T parseGenericInputStream(Parser<T> parser, InputStream inputStream)
throws InvalidProtocolBufferException {
return parser.parseFrom(inputStream);
}
At this point though you're writing a generic method for one line of code, which is kind of not worth it if you ask me.

No, there is not; you cannot deserialize a proto without knowing its type.
If you do know its type, then you can pass in a Builder for its type, however.
(Additionally, you can't call static methods on a type variable like T.)

Related

How to mock a method call using Mockito

I have the following problem using Mockito for unit testing:
I have this method:
#Override
public void handle(HttpExchange httpRequest) throws IOException {
Object[] outputResult = processRequest(httpRequest);
String response = (String) outputResult[0];
Integer responseCode = (Integer) outputResult[1];
httpRequest.sendResponseHeaders(responseCode, response.length());
OutputStream os = httpRequest.getResponseBody();
os.write(response.getBytes());
os.close();
}
And I want only to test this method, not the processRequestMethod that is called internally (that I would like to test separately in anthoer test), so I need to mock it and to check at the end of the test that the methods write and close of the OutputStream class have been called.
I have tried two ways, but no luck with none of them:
#Test
public void handleTest() throws IOException {
RequestHandler requestHandler=mock(RequestHandler.class);
String response = "Bad request";
int responseCode = HttpURLConnection.HTTP_BAD_REQUEST;
Object[] result={response,responseCode};
when(requestHandler.processRequest(anyObject())).thenReturn(result);
when (httpExchange.getResponseBody()).thenReturn(outputStream);
requestHandler.handle(httpExchange);
Mockito.verify(outputStream,times(1)).write(anyByte());
Mockito.verify(outputStream,times(1)).close();
}
With the code above, the processRequest method is not called, but neither is the handle method that I want to test, so the test is failing in the line:
Mockito.verify(outputStream,times(1)).write(anyByte());
Saying that this method was not called at all.
However if I add the parameter CALL_REAL_METHODS when creating the mock, like this:
#Test
public void handleTest() throws IOException {
RequestHandler requestHandler=mock(RequestHandler.class,CALLS_REAL_METHODS);
String response = "Bad request";
int responseCode = HttpURLConnection.HTTP_BAD_REQUEST;
Object[] result={response,responseCode};
when(requestHandler.processRequest(anyObject())).thenReturn(result);
when (httpExchange.getResponseBody()).thenReturn(outputStream);
requestHandler.handle(httpExchange);
Mockito.verify(outputStream,times(1)).write(anyByte());
Mockito.verify(outputStream,times(1)).close();
}
Then the processRequest method that I want to skip is actually called when the method executes this line:
when(requestHandler.processRequest(anyObject())).thenReturn(result);
Any clues of what can be wrong?
in your test instead of
RequestHandler requestHandler=mock(RequestHandler.class,CALLS_REAL_METHODS);
use Mockito.spy():
RequestHandler requestHandler=spy(RequestHandler.class);
doReturn(result).when(requestHandler).processRequest(httpRequest);
you may want the doReturn().when() form rather than the when().thenReturn() because the first does not execute the method whereas the latter does.
On the other hand I'd prefer to move processRequest() to another class where you can inject an instance of into RequestHandler which would make mocking more straight...

Strust2 type conversion error from String to byte array?

Struts 2 has implicit type conversion which take cares of user entered params type cast e.g. int, string , double ,boolean etc.
But my requirement is to convert rich text area input to byte array and for that I have created a custom type converter class.
public class StringToByteArrayConverter extends StrutsTypeConverter{
#Override
public Object convertFromString(Map context, String[] value, Class arg2) {
String val = value[0];
return val.getBytes() ;
}
#Override
public String convertToString(Map context, Object value) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os;
try {
os = new ObjectOutputStream(out);
os.writeObject(value);
return new String(out.toByteArray());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
And in model class I have specified the following annotation on setter of property
#TypeConversion(converter="org.package.name.StringToByteArrayConverter")
public void setVarName(byte[] varName) {
this.varName = varName;
}
The same annotation is applyed on getter method also.
Now everything seems fine I am getting correct data in Action method. But while displaying the data on jsp I am getting some extra symbols with original content.
eg. user input is :what is your name ?
it display on jsp : ¬íur[B¬óøTàxpwhat is your name ?
Any one has any Idea, What am I dong wrong ?
Start by specifying the correct Charset in the byte-to-string processing:
val.getBytes(); // wrong
val.getBytes("UTF-8"); // right
assuming you're working on UTF-8. Otherwise, just put the charset you're using, but never use val.getBytes(); that will take the platform-default charset, that might differ from your app's charset, creating conversion errors and artifacts like the ones you're getting now.
Then the ObjectOutputStream doesn't convince me. Try with a simple
#Override
public String convertToString(Map context, Object value) {
try {
return new String((byte[]) value, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
and eventually add logging for wrong usage, eg: if (value instanceof byte[]).. else LOG.warn....

How to handle exceptions that occur when instantiating a class object

java version "1.7.0_45"
Hello
I am initializing the class methods in the constructor. However, the new URL(uploadUrl) will throw an exception in the constructor. So if this happens the user shouldn't be able to continue. As the constructor cannot return anything, I am wondering that is the best way to handle this?
Many thanks for any suggestions,
public class MultipleFileTransfer {
private static final String TAG = MultipartUtility.class.getSimpleName();
private DataOutputStream dataOutputStream;
private FileInputStream fileInputStream;
private HttpURLConnection httpURLConnection;
private URL url;
public MultipleFileTransfer(final String uploadUrl) {
dataOutputStream = null;
fileInputStream = null;
httpURLConnection = null;
try {
url = new URL(uploadUrl);
} catch (MalformedURLException e) {
Log.wtf(TAG, e.getMessage()); /* <-- How to handle a failure */
}
}
/* Factory method that initializes the class methods and returns the class object */
public static MultipleFileTransfer getInstance(final String uploadUrl) {
/* Check that a valid url has been entered correctly */
if(!URLUtil.isValidUrl(uploadUrl)) {
Log.wtf(TAG, "Invalid url: " + uploadUrl);
return null;
}
return new MultipleFileTransfer(uploadUrl);
}
}
As the constructor cannot return anything, I am wondering that is the best way to handle this?
Typically, allow the exception to propagate to the caller, either directly or by wrapping it in your own higher-level abstraction exception. (In your case, just allowing it directly looks more appropriate.)
public MultipleFileTransfer(final String uploadUrl) throws MalformedURLException {
// -------------------------------------------------^
dataOutputStream = null;
fileInputStream = null;
httpURLConnection = null;
url = new URL(uploadUrl);
}
Since your instance isn't useful without the URL, it makes sense for construction to fail.
Or if you want to log it in the constructor (but if it's propagating, typically any logging if appropriate would be handled by the caller):
// Logging and re-throwing, but probably not recommended
public MultipleFileTransfer(final String uploadUrl) throws MalformedURLException {
// -------------------------------------------------^
dataOutputStream = null;
fileInputStream = null;
httpURLConnection = null;
try {
url = new URL(uploadUrl);
} catch (MalformedURLException e) {
Log.wtf(TAG, e.getMessage());
throw e; // <== Rethrowing
}
}
I can think of two decent ways to handle the situation:
(1) Let the constructor throw an exception. Either rethrow the same exception after logging, or throw a different exception. If the exception it throws isn't a RuntimeException (and MalformedURLException is not a RuntimeException), you'll need to add a throws clause to the constructor.
(2) Let the constructor create an object anyway, but mark it as an "invalid" object that cannot be used. I'd add an isValid() or isInvalid() method so that the caller can query whether it's valid. Other methods should throw IllegalStateException if they're called on an invalid object.
I don't think one is clearly better than the other. It depends on preference and perhaps on the design of the rest of the program.

Creating new instance from Class with constructor parameter

I have situation where my Java class needs to create a ton of certain kind of objects. I would like to give the name of the class of the objects that are created as a parameter. In addition, I need to give the created class a parameter in its constructor. I have something like
class Compressor {
Class ccos;
public Compressor(Class ccos) {
this.ccos = ccos;
}
public int getCompressedSize(byte[] array) {
OutputStream os = new ByteArrayOutputStream();
// the following doesn't work because ccos would need os as its constructor's parameter
OutputStream cos = (OutputStream) ccos.newInstance();
// ..
}
}
Do you have any ideas how I could remedy this?
Edit:
This is part of a research project where we need to evaluate the performance of multiple different compressors with multiple different inputs. Class ccos is a compressed OutputStream either from Java's standard library, Apache Compress Commons or lzma-java.
Currently I have the following which appears to work fine. Other ideas are welcome.
OutputStream os = new ByteArrayOutputStream();
OutputStream compressedOut = (OutputStream) ccos.getConstructor(OutputStream.class).newInstance(os);
final InputStream sourceIn = new ByteArrayInputStream(array);
You can use the Class.getConstructor(paramsTypes...) method and call newInstance(..) on the constructor. In your case:
Compressor.class.getConstructor(Class.class).newInstance(Some.class);
Using Spring ClassUtils and BeanUtils classes you can avoid dealing with those tedious exceptions that is Spring handling for you :
Constructor<Car> constructor = ClassUtils.getConstructorIfAvailable(Wheels.class, Etc.class);
Car car = BeanUtils.instantiateClass(constructor, new Wheels(), new Etc());
You have to get to the relevant Constructor object (e.g. via Class.getConstructors or Class.getConstructor) and then call constructor.newInstance, giving it the arguments it requires.
An example you can use is as follows:
lets say conn is a connection to the database.
Class[] btarray = { conn.getClass() };
try {
if (classname != null) {
pmap = (Mapper) Class.forName(classname)
.getConstructor(btarray)
.newInstance(
new Object[] { conn }
);
}
} catch (Throwable x) {
x.printStackTrace(Log.out);
}
btarray allows you to pass in arguments to the constructor.
class Compresor<T> {
private Class<? extends T> clazz;
Compresor(final Class<? extends T> cls){
this.clazz = cls
}
}

java constructor to assign the entire class not just fields

my system is both jibx and a legacy xml app and i want to build a constructor that can take a string of xml and unmarshal it into its own class. like this:
public ActiveBankTO(String xmlIn)
{
try
{
ByteArrayInputStream bin = new ByteArrayInputStream(xmlIn.getBytes());
IBindingFactory bfact;
bfact = BindingDirectory.getFactory(ActiveBankTO.class);
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
this = (ActiveBankTO) uctx.unmarshalDocument(bin, null);
} catch (JiBXException e)
{
e.printStackTrace();
}
}
but obviously i cant assign "this" as a variable. is there a way to make this work? i realize i can put this into a static method that can be used, or a few other tricks to make it work, but this is something that has come up on several projects in various forms and i was wondering if this particular method is possible.
No, it's not possible. The static method solution is the best idea.
public static ActiveBankTO parseActiveBankTO(String xmlIn) {
ActiveBankTO newTO = null;
try {
ByteArrayInputStream bin = new ByteArrayInputStream(xmlIn.getBytes());
IBindingFactory bfact;
bfact = BindingDirectory.getFactory(ActiveBankTO.class);
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
newTO = (ActiveBankTO) uctx.unmarshalDocument(bin, null);
} catch (JiBXException e) {
e.printStackTrace();
}
return newTO;
}
No. ti's not possible in the constructor. A static factory method is the only real way (you can't even cheat like this in bytecode).

Categories

Resources