Re: [javacpp-project] Returning Strings by value, and passing by value or by const-ref

38 views
Skip to first unread message

Samuel Audet

unread,
Feb 2, 2019, 5:57:50 PM2/2/19
to javacpp...@googlegroups.com, Ioannis Moschakis
Hi,

There is no easy way to differentiate between types declared with const, *, and & at the moment, or their parameter names, but this is something I'm thinking about:

For now the way to work around this is by using Info.javaText() where required:

In this case, we could use something like this:
infoMap.put(new Info("ClassA::getIt").javaText("@Virtual(true) public native @Const({false, false, true}) @Cast({\"const char*\", \"std::string\"}) String getIt();"));
infoMap.put(new Info("ClassA::getWhich").javaText("@Virtual(true) public native @Const({false, false, true}) @Cast({\"const char*\", \"std::string\"}) String getWhich(@Cast({\"const char*\", \"const std::string&\"}) @StdString arg);"));
We can also replace @Cast({"const char*", "std::string"}) @StdString with your @StdStringVal, for example. Sounds good?

Samuel

On 2/3/19 12:23 AM, Ioannis Moschakis wrote:
Hi all,

This may sound like a dumb question but I've spent so much time and I'm still at a loss of how to do this,

I've got a class like so:

using String = std::string; // just stating that i'm using type aliases in cases that creates a problem
using StringVectorT = std::vector<String>; 

class ClassA
{
public:
   virtual String getIt() const = 0;
   virtual String getWhich(const String& arg) const = 0;
   virtual StringVectorT getAll() const = 0;
}

I'm trying to expose said class using the following config:


public class VacuumConfig implements InfoMapper {

@Properties(..)
public class Config implements InfoMapper {

public void map(InfoMap infoMap) {

      infoMap.put(new Info("std::string", "String").annotations("@StdString").pointerTypes("BytePointer"));
                        infoMap.put(new Info("std::vector<std::string>", "StringVectorT").pointerTypes("StringVector").define());
                         
      infoMap.put(new Info("ClassA").pointerTypes("ClassA").purify(false).virtualize());
     }
}

Since @StdString maps to std::basic_string<char>& the overriding function (created due to virtualize) has an conflicting return type (std::basic_string<char>& instead of String (aka std::string).

I've tried other variations:
  • infoMap.put(new Info("std::string", "veltio::vacuum::String").valueTypes("String").pointerTypes("@StdString BytePointer")); No effect, return const char* instead of basic_string
  • infoMap.put(new Info("std::string", "veltio::vacuum::String").valueTypes("@Cast(\"std::string\") String").pointerTypes("@StdString BytePointer")); This solves the problem for the method getIt but creates a whole lot other problems for StringVector (and any other type of structure e.g. maps) since const char* cannot be cast to std::string plus manual modification of the produced java file is required b/c things like this appear in the declaration of StringVector:
    •  @Cast("std::string") String[] array = new @Cast("std::string") String[size() < Integer.MAX_VALUE ? (int)size() : Integer.MAX_VALUE];
  • I've even tried defining this:
   @Documented @Retention(RetentionPolicy.RUNTIME)
   @Target({ElementType.METHOD, ElementType.PARAMETER})
   @Cast({"std::basic_string"}) @Adapter("StringAdapter")
   public @interface StdStringVal {
       String value() default "char";
   }
    • This creates a problem for the method accepting const String& as an argument (i.e. getWhich).
I've tried searching in javacpp-presets but could pin down a solution to this..

What I need is a mapping that allows methods that accept strings by-value or by const-ref and return string by-value to be able to work okay, is there a way currently to do this?



Ioannis Moschakis

unread,
Feb 3, 2019, 5:45:35 AM2/3/19
to javacpp
Thanks for the prompt answer Samuel! Yeap
at least I didn't miss anything blatant so all good will try this approach thanks for all the work you've put in!

Ioannis Moschakis

unread,
Feb 3, 2019, 1:52:43 PM2/3/19
to javacpp
Hi Samuel,

Unfortunately, this doesn't work either, getIt gets declared like so:

virtual const char* getIt() const;

The dummy implementation get declared like so:

 const char* super_getLabel() { throw JavaCPP_exception("Cannot call pure virtual function ::getIt()."); }

If I change it to @Cast({\"std::string\", \"std::string\"}) then the declaration is okay but then during the definition of the:

JNIEXPORT jstring JNICALL ..._getIt(JNIEnv* env..)
{
...
rptr = (std::string)(const char*)(dynamic_cast<...>(ptr) != NULL ? ((...)ptr)->super_getName() : ptr->getName())
}

This fails b/c you cannot cast std::string to const char* and even if the casts are removed manually it still needs a .c_str() at the end since rptr is const char*.

I can always opt to create a intermediate method that returns const char* and override that in Java, but if there are any other ideas please let me know.

Thanks again!

Ioannis Moschakis

unread,
Feb 3, 2019, 1:54:06 PM2/3/19
to javacpp
Opps too fast made a few mistakes, corrected below:

On Sunday, February 3, 2019 at 8:52:43 PM UTC+2, Ioannis Moschakis wrote:
Hi Samuel,

Unfortunately, this doesn't work either, getIt gets declared like so:

virtual const char* getIt() const;

The dummy implementation get declared like so:

 const char* super_getIt() { throw JavaCPP_exception("Cannot call pure virtual function ::getIt()."); }

If I change it to @Cast({\"std::string\", \"std::string\"}) then the declaration is okay but then during the definition of the:

JNIEXPORT jstring JNICALL ..._getIt(JNIEnv* env..)
{
...
rptr = (std::string)(const char*)(dynamic_cast<...>(ptr) != NULL ? ((...)ptr)->super_getIt() : ptr->getIt())

Samuel Audet

unread,
Feb 3, 2019, 8:15:44 PM2/3/19
to javacpp...@googlegroups.com, Ioannis Moschakis
I'm unable to reproduce this issue with either JavaCPP 1.4.4 or 1.4.5-SNAPSHOT.
Could you post a small but complete code snippet that fails?

Ioannis Moschakis

unread,
Feb 15, 2019, 12:03:15 PM2/15/19
to javacpp

Hi Samuel,

Sorry it took me this long to reply, I've attached a zip with the with an example of what is not working as described your previous instructions lead to generator generating code that doesn't compile.

Please let me know if I can do anything more to help, in the mean time I've fixed my problem by using proxy methods that return const char*.

Thanks,
Ioannis
javacppexample.zip

Samuel Audet

unread,
Feb 15, 2019, 8:11:54 PM2/15/19
to javacpp...@googlegroups.com, Ioannis Moschakis
Hi,

After fixing the Infos to the following, it compiles just fine:
infoMap.put(new Info("TestClass::getIt").javaText("@Virtual(true) public native @Const({false, false, true}) @Cast({\"const char*\", \"std::string\"}) @StdString String getIt();"))
infoMap.put(new Info("TestClass::getWhich").javaText("@Virtual(true) public native @Const({false, false, true}) @Cast({\"const char*\", \"std::string\"}) @StdString String getWhich(@Cast({\"const char*\", \"const std::string&\"}) @StdString String arg);"));
Can you confirm?

Samuel

Ioannis Moschakis

unread,
Feb 16, 2019, 11:08:16 AM2/16/19
to javacpp
Hi Samuel,

Confirmed it works fine now, thanks a lot for all the help!

Cheers,
Ioannis
Reply all
Reply to author
Forward
0 new messages