JNA cast to struct from void** - java

I have to call a C library that receives as parameter a void**; it converts the void** into a known structure (depending on function internal information) then allocates memory and fills it with data.
I don't know how to call it from Java.
Below are some details:
The struct:
typedef struct {
uint32_t Size[64];
uint16_t *Datas[64];
} MyStruct_t;
The C function
int Cfunc( void **Evt) {
int i;
MyStruct_t *s;
s = (MyStruct_t *) malloc(sizeof(MyStruct_t));
for (i=0; i<8; i++) {
(s)->Size[i] = 512;
(s)->Datas[i] = malloc(512 * sizeof (short));
}
for (i=8; i<63; i++) {
(s)->Size[i] = 0;
(s)->Datas[i] = NULL;
}
*Evt = s;
}
My JNA wrapper class:
public class MyStruct_t extends Structure<MyStruct_t, MyStruct_t.ByValue, MyStruct_t.ByReference > {
/// the number of samples stored in Datas array
public int[] Size = new int[64];
/// the array of Size samples
public ShortByReference[] Datas = new ShortByReference[64];
public MyStruct_t() {
super();
initFieldOrder();
}
protected void initFieldOrder() {
setFieldOrder(new String[]{"Size", "Datas"});
}
public MyStruct_t(int Size[], ShortByReference Datas[]) {
super();
if (Size.length != this.Size.length)
throw new IllegalArgumentException("Wrong array size !");
this.Size = Size;
if (Datas.length != this.Datas.length)
throw new IllegalArgumentException("Wrong array size !");
this.Datas = Datas;
initFieldOrder();
}
#Override protected ByReference newByReference() { return new ByReference(); }
#Override protected ByValue newByValue() { return new ByValue(); }
#Override protected MyStruct_t newInstance() { return new MyStruct_t(); }
public static MyStruct_t[] newArray(int arrayLength) {
return Structure.newArray(MyStruct_t.class, arrayLength);
}
public static class ByReference extends MyStruct_t implements Structure.ByReference {};
public static class ByValue extends MyStruct_t implements Structure.ByValue {};
}
The Java function declaration:
public static native int Cfunc(MyStruct_t.ByReference Evt);
public static native int Cfunc(PointerByReference Evt);
If I call the Cfunc passing a PointerByReference I can see that memory is allocated and something is present but I don't know how to cast (?) it to the real structure (MyStruct_t).
If I call the Cfunc passing a MyStruct_t.ByReference, I find the structure not well allocated and values inside are not the expected.
What am I doing wrong?

To be clear, you are providing the address of a pointer. The callee sets the pointer value to the address of a struct which it allocates.
First, you pass the address of the pointer (a.k.a PointerByReference):
public static native int Cfunc(PointerByReference Evt);
Then, you extract the "returned" pointer value:
PointerByReference pref = new PointerByReference();
lib.CFunc(pref);
Pointer p = pref.getValue();
Then, you can create a new instance of your structure based on the "returned" pointer value:
MyStruct s = new MyStruct(p);
This, of course, requires that you implement the Pointer-based ctor for your structure:
public MyStruct(Pointer p) {
super(p);
read();
}

I found the mistake! I was using Structure class from jnaerator, I removed the jnaerator Structure class and used JNA Structure and now it works.
here is the modified and working java class:
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.ShortByReference;
public class t_t extends Structure {
public int[] lsize = new int[64];
public Pointer[] ldata = new Pointer[64];
public t_t() {
super();
initFieldOrder();
}
protected void initFieldOrder() {
setFieldOrder(new String[]{"size", "data"});
}
public t_t(int size[], Pointer data[]) {
super();
if (size.length != this.lsize.length)
throw new IllegalArgumentException("Wrong array size !");
this.lsize = size;
if (data.length != this.ldata.length)
throw new IllegalArgumentException("Wrong array size !");
this.ldata = data;
initFieldOrder();
}
public t_t(Pointer p){
super(p);
read();
}
public short[] getData(int i) {
if (this.lsize[i] == 0) return null;
return this.ldata[i].getShortArray(0, this.lsize[i]);
}
public int getSize(int i) {
return this.lsize[i];
}
public static class ByReference extends t_t implements Structure.ByReference {
};
public static class ByValue extends t_t implements Structure.ByValue {
};
}
Thanks technomage for the tip!
p1906

Related

How do I properly map CERT_SELECT_STRUCT in JNA

I am using jna-4.5.1 in my Java Project.
This is cryptdlg structure CERT_SELECT_STRUCT I want to replicate.
typedef struct tagCSSA {
DWORD dwSize;
HWND hwndParent;
HINSTANCE hInstance;
LPCSTR pTemplateName;
DWORD dwFlags;
LPCSTR szTitle;
DWORD cCertStore;
HCERTSTORE *arrayCertStore;
LPCSTR szPurposeOid;
DWORD cCertContext;
PCCERT_CONTEXT *arrayCertContext;
LPARAM lCustData;
PFNCMHOOKPROC pfnHook;
PFNCMFILTERPROC pfnFilter;
LPCSTR szHelpFileName;
DWORD dwHelpId;
HCRYPTPROV hprov;
} CERT_SELECT_STRUCT_A, *PCERT_SELECT_STRUCT_A;
Sample Java code for my project.
public class Crypto {
public interface Cryptdlg extends Library {
Cryptdlg INSTANCE = (Cryptdlg) Native.loadLibrary("Cryptdlg", Cryptdlg.class, W32APIOptions.DEFAULT_OPTIONS);
public boolean CertSelectCertificate(CERT_SELECT_STRUCT pCertSelectInfo);
public static class CERT_SELECT_STRUCT extends Structure {
private static final List<String> fieldOrder = createFieldsOrder("dwSize", "hwndParent", "hInstance",
"pTemplateName", "dwFlags", "szTitle", "cCertStore", "arrayCertStore", "szPurposeOid",
"cCertContext", "arrayCertContext", "lCustData", "pfnHook", "pfnFilter", "szHelpFileName",
"dwHelpId", "hprov");
public static class ByReference extends CERT_SELECT_STRUCT implements Structure.ByReference {
}
public int dwSize = size();
public HWND hwndParent;
public HINSTANCE hInstance;
public String pTemplateName;
public int dwFlags;
public String szTitle;
public int cCertStore;
public Pointer arrayCertStore;
public String szPurposeOid;
public int cCertContext;
public Pointer arrayCertContext;
public WinDef.LPARAM lCustData;
public Pointer pfnHook = null;
public Pointer pfnFilter = null;
public String szHelpFileName;
public int dwHelpId;
public HCRYPTPROV hprov;
public CERT_SELECT_STRUCT() {
super();
}
public WinCrypt.CERT_CONTEXT[] getArrayCertContext() {
WinCrypt.CERT_CONTEXT[] elements = new WinCrypt.CERT_CONTEXT[cCertContext];
for (int i = 0; i < elements.length; i++) {
elements[i] = (WinCrypt.CERT_CONTEXT) Structure.newInstance(WinCrypt.CERT_CONTEXT.class,
arrayCertContext.getPointer(i * Native.POINTER_SIZE));
elements[i].read();
}
return elements;
}
public void setArrayCertContext(WinCrypt.CERT_CONTEXT[] arrayCertContexts) {
if (arrayCertContexts == null || arrayCertContexts.length == 0) {
arrayCertContext = null;
cCertContext = 0;
} else {
cCertContext = arrayCertContexts.length;
Memory mem = new Memory(Native.POINTER_SIZE * arrayCertContexts.length);
for (int i = 0; i < arrayCertContexts.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, arrayCertContexts[i].getPointer());
}
arrayCertContext = mem;
}
}
public void setArrayCertStore(WinCrypt.HCERTSTORE[] stores) {
if (stores == null || stores.length == 0) {
arrayCertStore = null;
cCertStore = 0;
} else {
Memory mem = new Memory(Native.POINTER_SIZE * stores.length);
for (int i = 0; i < stores.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, stores[i].getPointer());
}
cCertStore = stores.length;
arrayCertStore = mem;
}
}
public WinCrypt.HCERTSTORE[] getArrayCertStore() {
if (arrayCertStore == null || cCertStore == 0) {
return new WinCrypt.HCERTSTORE[0];
} else {
WinCrypt.HCERTSTORE[] result = new WinCrypt.HCERTSTORE[cCertStore];
for (int i = 0; i < result.length; i++) {
result[i] = new WinCrypt.HCERTSTORE(arrayCertStore.getPointer(i * Native.POINTER_SIZE));
}
return result;
}
}
#Override
protected List<String> getFieldOrder() {
return fieldOrder;
}
}
}
public void CertSelect() {
Cryptdlg cryptdlg = Cryptdlg.INSTANCE;
...// parentHwnd and hCertStore are initalized and passed to this method
Cryptdlg.CERT_SELECT_STRUCT certSel = new Cryptdlg.CERT_SELECT_STRUCT();
WinCrypt.CERT_CONTEXT[] pContexts = new WinCrypt.CERT_CONTEXT[1];
certSel.hwndParent = parentHwnd;
certSel.szTitle = "title";
certSel.cCertStore = 1;
certSel.setArrayCertStore(new WinCrypt.HCERTSTORE[] {hCertStore});
pCertSelectInfo.cCertContext = 1;
pContexts[0] = new WinCrypt.CERT_CONTEXT.ByReference();
certSel.setArrayCertContext(pContexts);
cryptdlg.CertSelectCertificate(certSel); //line 60
...
}
}
When I call this method I get "java.lang.Error: Invalid memory access" at the dll call cryptdlg.CertSelectCertificate(certSel) at line 60 above.
java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:419)
at com.sun.jna.Function.invoke(Function.java:354)
at com.sun.jna.Library$Handler.invoke(Library.java:244)
at com.sun.proxy.$Proxy13.CertSelect(Unknown Source)
at com.project.Crypto.CertSelect(Crypto.java:60)
I am not sure why we are getting the exception. I followed the example mentioned here.
[UPDATE]
For what its worth,
When I modify the type of "setArrayCertStore" from Pointer to HCERTSTORE[] I am not getting any exception but no certificate are getting pulled.
It makes me think if arrayCertStore is initalized correctly or not.
WinCrypt.HCERTSTORE[] cStoreArray = new WinCrypt.HCERTSTORE[1];
pCertSelectInfo.cCertStore = 1;
cStoreArray[0] = hCertStore;
pCertSelectInfo.arrayCertStore = cStoreArray;
And the structure definition is changed as follows
public WinCrypt.HCERTSTORE[] arrayCertStore;
And HCRYPTPROV is defined as
public static class HCRYPTPROV extends BaseTSD.ULONG_PTR {
public HCRYPTPROV() {}
public HCRYPTPROV(long value) {
super(value);
}
}
==================================
[EDIT]
After discussion with Daniel and other people. Here is the updated code which works
public class Crypto {
public interface Cryptdlg extends Library {
Cryptdlg INSTANCE = (Cryptdlg) Native.loadLibrary("Cryptdlg", Cryptdlg.class, W32APIOptions.DEFAULT_OPTIONS);
public boolean CertSelectCertificate(CERT_SELECT_STRUCT pCertSelectInfo);
public static class CERT_SELECT_STRUCT extends Structure {
private static final List<String> fieldOrder = createFieldsOrder("dwSize", "hwndParent", "hInstance",
"pTemplateName", "dwFlags", "szTitle", "cCertStore", "arrayCertStore", "szPurposeOid",
"cCertContext", "arrayCertContext", "lCustData", "pfnHook", "pfnFilter", "szHelpFileName",
"dwHelpId", "hprov");
public static class ByReference extends CERT_SELECT_STRUCT implements Structure.ByReference {
}
public int dwSize;
public HWND hwndParent;
public HINSTANCE hInstance;
public String pTemplateName;
public int dwFlags;
public String szTitle;
public int cCertStore;
public Pointer arrayCertStore;
public String szPurposeOid;
public int cCertContext;
public Pointer arrayCertContext;
public WinDef.LPARAM lCustData;
public Pointer pfnHook = null;
public Pointer pfnFilter = null;
public String szHelpFileName;
public int dwHelpId;
public HCRYPTPROV hprov;
public CERT_SELECT_STRUCT() {
super();
}
public WinCrypt.CERT_CONTEXT[] getArrayCertContext() {
WinCrypt.CERT_CONTEXT[] elements = new WinCrypt.CERT_CONTEXT[cCertContext];
for (int i = 0; i < elements.length; i++) {
elements[i] = (WinCrypt.CERT_CONTEXT) Structure.newInstance(WinCrypt.CERT_CONTEXT.class,
arrayCertContext.getPointer(i * Native.POINTER_SIZE));
elements[i].read();
}
return elements;
}
public void setArrayCertContext(WinCrypt.CERT_CONTEXT[] arrayCertContexts) {
if (arrayCertContexts == null || arrayCertContexts.length == 0) {
arrayCertContext = null;
cCertContext = 0;
} else {
cCertContext = arrayCertContexts.length;
Memory mem = new Memory(Native.POINTER_SIZE * arrayCertContexts.length);
for (int i = 0; i < arrayCertContexts.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, arrayCertContexts[i].getPointer());
}
arrayCertContext = mem;
}
}
public void setArrayCertStore(WinCrypt.HCERTSTORE[] stores) {
if (stores == null || stores.length == 0) {
arrayCertStore = null;
cCertStore = 0;
} else {
Memory mem = new Memory(Native.POINTER_SIZE * stores.length);
for (int i = 0; i < stores.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, stores[i].getPointer());
}
cCertStore = stores.length;
arrayCertStore = mem;
}
}
public WinCrypt.HCERTSTORE[] getArrayCertStore() {
if (arrayCertStore == null || cCertStore == 0) {
return new WinCrypt.HCERTSTORE[0];
} else {
WinCrypt.HCERTSTORE[] result = new WinCrypt.HCERTSTORE[cCertStore];
for (int i = 0; i < result.length; i++) {
result[i] = new WinCrypt.HCERTSTORE(arrayCertStore.getPointer(i * Native.POINTER_SIZE));
}
return result;
}
}
#Override
public void write() {
this.dwSize = size();
super.write();
}
#Override
protected List<String> getFieldOrder() {
return fieldOrder;
}
}
}
public void CertSelect() {
Cryptdlg cryptdlg = Cryptdlg.INSTANCE;
Cryptdlg.CERT_SELECT_STRUCT certSel = new Cryptdlg.CERT_SELECT_STRUCT();
certSel.hwndParent = parentHwnd;
certSel.szTitle = "title";
certSel.cCertStore = 1;
certSel.setArrayCertStore(new WinCrypt.HCERTSTORE[] {hCertStore});
pCertSelectInfo.cCertContext = 1;
pCertSelectInfo.arrayCertContext = new Memory(Native.POINTER_SIZE);
pCertSelectInfo.arrayCertContext.setPointer(0, Pointer.NULL);
cryptdlg.CertSelectCertificate(certSel);
...
}
}
There are a few potential problem areas.
First, you are mixing the ANSI and Unicode versions.
The CertSelectCertificate() function has two variants, one ending in A and one in W. The -A functions are the ANSI (8-bit characters) while the -W variants are for Unicode/Wide-string (16 bit characters). The main difference in the methods is the number of characters in the strings in the CERT_SELECT_STRUCT structure., which similarly has two variants, CERT_SELECT_STRUCT_A and CERT_SELECT_STRUCT_W.
JNA automatically maps you to the correct version (the -W version in almost all cases in modern operating systems) using its default type mapper. You should probably add that type mapper explicitly in your library loading using the default options for Win32 libraries:
Cryptdlg INSTANCE = (Cryptdlg) Native.loadLibrary("Cryptdlg", Cryptdlg.class,
W32APIOptions.DEFAULT_OPTIONS);
However, you have an explicit call to use the -A type mapper in your CERT_SELECT_STRUCT() constructor:
public CERT_SELECT_STRUCT() {
super(W32APITypeMapper.ASCII);
}
This forces it to use the -A version of the structure, which only has 8 bits per character in its strings. You should just call super().
A second possibility, while not obvious from the docs, is that the first element, dwSize, is supposed to be the size of the structure. You should put that in your constructor:
this.dwSize = this.size();
A third possibility (and the most likely cause, if I were to guess) is in the line when you set the contents of the arrayCertContext field. It is documented as:
A pointer to an array of CERT_CONTEXT structures.
You define the array on the Java side as a structure (which has its own pointer) and manually set it into memory, but instead of populating the CERT_CONTEXT structure you put a Pointer there:
pContexts[0] = new WinCrypt.CERT_CONTEXT.ByReference();
That ends up filling up the first 8 bytes of the "structure" with the pointer address you just created, the first 4 bytes of which are assigned to dwCertEncodingType and the next 4 bytes (plus 4 null bytes) go to the pointer value of a ByteByReference() field.
Also, easier than your allocation of memory, allocation of arrays of structures could be done like this:
WinCrypt.CERT_CONTEXT[] pContextArray =
(WinCrypt.CERT_CONTEXT[]) new WinCrypt.CERT_CONTEXT().toArray(1);
As an aside, you might find structure definitions more streamlined in JNA 5.x (currently 5.6.0) which include a #FieldOrder annotation as a preferred method of creating the field order list.

how to specify a JNR Pointer like that of python ctypes

Using python's ctypes, it's possible to specify a pointer that takes a type:
class METADATA(Structure):
_fields_ = [("classes", c_int),
("names", POINTER(c_char_p))]
With JNR, it looks like this:
public static class Metadata extends Struct{
public Metadata(jnr.ffi.Runtime rt) {
super(rt);
}
public final Struct.Unsigned32 classes = new Struct.Unsigned32();
public final Struct.Pointer names = new Struct.Pointer();
}
However, is it possible to type the names field as a Pointer to a String?
I'm not familiar with python's ctypes but assuming the type of names is either char* or char** you could try to use one of the following approaches.
For a shared library,
#include <stdlib.h>
#include <stdio.h>
struct MyStruct {
int classes;
char *names;
char **names2;
};
struct MyStruct *get_my_struct() {
struct MyStruct *my_struct = malloc(sizeof(struct MyStruct));
my_struct->classes = 42;
my_struct->names = "My Names";
char **names2 = calloc(2, sizeof(char *));
names2[0] = "Stack";
names2[1] = "Overflow";
my_struct->names2 = names2;
return my_struct;
}
The struct can be defined as follows
public static class MyStruct extends Struct {
public MyStruct(Runtime runtime) {
super(runtime);
}
public final Struct.Signed32 classes = new Struct.Signed32();
// For char* the support is built-in
public final Struct.String names = new Struct.UTF8StringRef();
// For char** you could wrap a pointer and override getStringMemory
public final UTF8StringRef[] names2 = UTF8StringRefArray(new Struct.Pointer(), 2);
protected UTF8StringRef[] UTF8StringRefArray(Pointer pointer, int stringLength) {
UTF8StringRef[] array = new UTF8StringRef[stringLength];
for (int i = 0; i < array.length; i++) {
int index = i;
array[i] = new UTF8StringRef() {
#Override
protected jnr.ffi.Pointer getStringMemory() {
return pointer.get().getPointer(getRuntime().addressSize() * index);
}
};
}
return array;
}
}
For the above, the following code will print 42 My Names are Stack, Overflow.
public interface MyLib {
MyStruct get_my_struct();
}
public static void main(String[] args) {
MyLib mylib = LibraryLoader.create(MyLib.class).load("mylib.so");
MyStruct myStruct = mylib.get_my_struct();
System.out.printf("%d %s are %s, %s", myStruct.classes.get(), myStruct.names.get(),
myStruct.names2[0].get(), myStruct.names2[1].get());
}

In java, can you use the builder pattern with required and reassignable fields?

This is related to the following question:
How to improve the builder pattern?
I'm curious whether it's possible to implement a builder with the following properties:
Some or all parameters are required
No method receives many parameters (i.e., no list of defaults supplied to the initial builder factory method)
All builder fields can be reassigned an arbitrary number of times
The compiler should check that all parameters have been set
It is ok to require that parameters are initially set in some order, but once any parameter is set, all following builders can have this parameter set again (i.e., you can reassign the value of any field of the builder you wish)
No duplicate code should exist for setters (e.g., no overriding setter methods in builder subtypes)
One failed attempt is below (empty private constructors omitted). Consider the following toy builder implementation, and note that line with "Foo f2" has a compiler error because the inherited setter for a returns a BuilderB, not a BuilderFinal. Is there a way to use the java type system to parameterize the return types of the setters to achieve the above goals, or achieve them some other way.
public final class Foo {
public final int a;
public final int b;
public final int c;
private Foo(
int a,
int b,
int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static BuilderA newBuilder() {
return new BuilderC();
}
public static class BuilderA {
private volatile int a;
public BuilderB a(int v) {
a = v;
return (BuilderB) this;
}
public int a() {
return a;
}
}
public static class BuilderB extends BuilderA {
private volatile int b;
public BuilderC b(int v) {
b = v;
return (BuilderC) this;
}
public int b() {
return b;
}
}
public static class BuilderC extends BuilderB {
private volatile int c;
public BuilderFinal c(int v) {
c = v;
return (BuilderFinal) this;
}
public int c() {
return c;
}
}
public static class BuilderFinal extends BuilderC {
public Foo build() {
return new Foo(
a(),
b(),
c());
}
}
public static void main(String[] args) {
Foo f1 = newBuilder().a(1).b(2).c(3).build();
Foo f2 = newBuilder().a(1).b(2).c(3).a(4).build();
}
}
Your requirements are really hard, but see if this generic solution fits the bill:
public final class Foo {
public final int a;
public final int b;
public final int c;
private Foo(
int a,
int b,
int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static BuilderA<? extends BuilderB<?>> newBuilder() {
return new BuilderFinal();
}
public static class BuilderA<T extends BuilderB<?>> {
private volatile int a;
#SuppressWarnings("unchecked")
public T a(int v) {
a = v;
return (T) this;
}
public int a() {
return a;
}
}
public static class BuilderB<T extends BuilderC<?>> extends BuilderA<T> {
private volatile int b;
#SuppressWarnings("unchecked")
public T b(int v) {
b = v;
return (T) this;
}
public int b() {
return b;
}
}
public static class BuilderC<T extends BuilderFinal> extends BuilderB<T> {
private volatile int c;
#SuppressWarnings("unchecked")
public T c(int v) {
c = v;
return (T) this;
}
public int c() {
return c;
}
}
public static class BuilderFinal extends BuilderC<BuilderFinal> {
public Foo build() {
return new Foo(
a(),
b(),
c());
}
}
public static void main(String[] args) {
Foo f1 = newBuilder().a(1).b(2).c(3).build();
Foo f2 = newBuilder().a(1).b(2).c(3).a(4).build();
}
}
To my knowledge the builder pattern should be used in case multiple parameters are used that make the invocation rather complicated as parameters might swap positions or not make it obviously clear what which parameter is for.
A rule of thumb would be to require compulsory parameters within the constructor of the builder and optional parameters within the methods. However, often more than 4 parameters may be required which makes the invocation again rather unclear and the pattern redundant. So a split up into default constructor and parameter setting for each parameter can also be used.
The checks should happen in a own method which is invoked within the build-method so you could invoke it using super. Compile-time security is only guaranteed on the correct data types (only exception - null is possible to, this has to be fetched within the checkParameters()-method). You can however force that all required parameters are set on requiring them within the Builder constructor - but as mentioned before, this may lead to a redundant pattern.
import java.util.ArrayList;
import java.util.List;
public class C
{
public static class Builder<T extends C, B extends C.Builder<? extends C,? extends B>> extends AbstractBuilder<C>
{
protected String comp1;
protected String comp2;
protected int comp3;
protected int comp4;
protected int comp5;
protected List<Object> comp6 = new ArrayList<>();
protected String optional1;
protected List<Object> optional2 = new ArrayList<>();
public Builder()
{
}
public B withComp1(String comp1)
{
this.comp1 = comp1;
return (B)this;
}
public B withComp2(String comp2)
{
this.comp2 = comp2;
return (B)this;
}
public B withComp3(int comp3)
{
this.comp3 = comp3;
return (B)this;
}
public B withComp4(int comp4)
{
this.comp4 = comp4;
return (B)this;
}
public B withComp5(int comp5)
{
this.comp5 = comp5;
return (B)this;
}
public B withComp6(Object comp6)
{
this.comp6.add(comp6);
return (B)this;
}
public B withOptional1(String optional1)
{
this.optional1 = optional1;
return (B)this;
}
public B withOptional2(Object optional2)
{
this.optional2.add(optional2);
return (B)this;
}
#Override
protected void checkParameters() throws BuildException
{
if (this.comp1 == null)
throw new BuildException("Comp1 violates the rules");
if (this.comp2 == null)
throw new BuildException("Comp2 violates the rules");
if (this.comp3 == 0)
throw new BuildException("Comp3 violates the rules");
if (this.comp4 == 0)
throw new BuildException("Comp4 violates the rules");
if (this.comp5 == 0)
throw new BuildException("Comp5 violates the rules");
if (this.comp6 == null)
throw new BuildException("Comp6 violates the rules");
}
#Override
public T build() throws BuildException
{
this.checkParameters();
C c = new C(this.comp1, this.comp2,this.comp3, this.comp4, this.comp5, this.comp6);
c.setOptional1(this.optional1);
c.setOptional2(this.optional2);
return (T)c;
}
}
private final String comp1;
private final String comp2;
private final int comp3;
private final int comp4;
private final int comp5;
private final List<?> comp6;
private String optional1;
private List<?> optional2;
protected C(String comp1, String comp2, int comp3, int comp4, int comp5, List<?> comp6)
{
this.comp1 = comp1;
this.comp2 = comp2;
this.comp3 = comp3;
this.comp4 = comp4;
this.comp5 = comp5;
this.comp6 = comp6;
}
public void setOptional1(String optional1)
{
this.optional1 = optional1;
}
public void setOptional2(List<?> optional2)
{
this.optional2 = optional2;
}
// further methods omitted
#Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(this.comp1);
sb.append(", ");
sb.append(this.comp2);
sb.append(", ");
sb.append(this.comp3);
sb.append(", ");
sb.append(this.comp4);
sb.append(", ");
sb.append(this.comp5);
sb.append(", ");
sb.append(this.comp6);
return sb.toString();
}
}
On extending D from C and also the builder, you need to override the checkParameters() and build() method. Due to the use of Generics the correct type will be return on invoking build()
import java.util.List;
public class D extends C
{
public static class Builder<T extends D, B extends D.Builder<? extends D, ? extends B>> extends C.Builder<D, Builder<D, B>>
{
protected String comp7;
public Builder()
{
}
public B withComp7(String comp7)
{
this.comp7 = comp7;
return (B)this;
}
#Override
public void checkParameters() throws BuildException
{
super.checkParameters();
if (comp7 == null)
throw new BuildException("Comp7 violates the rules");
}
#Override
public T build() throws BuildException
{
this.checkParameters();
D d = new D(this.comp1, this.comp2, this.comp3, this.comp4, this.comp5, this.comp6, this.comp7);
if (this.optional1 != null)
d.setOptional1(optional1);
if (this.optional2 != null)
d.setOptional2(optional2);
return (T)d;
}
}
protected String comp7;
protected D(String comp1, String comp2, int comp3, int comp4, int comp5, List<?> comp6, String comp7)
{
super(comp1, comp2, comp3, comp4, comp5, comp6);
this.comp7 = comp7;
}
#Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append(", ");
sb.append(this.comp7);
return sb.toString();
}
}
The abstract builder class is quite simple:
public abstract class AbstractBuilder<T>
{
protected abstract void checkParameters() throws BuildException;
public abstract <T> T build() throws BuildException;
}
The exception is simple too:
public class BuildException extends Exception
{
public BuildException(String msg)
{
super(msg);
}
}
And last but not least the main method:
public static void main(String ... args)
{
try
{
C c = new C.Builder<>().withComp1("a1").withComp2("a2").withComp3(1)
.withComp4(4).withComp5(5).withComp6("lala").build();
System.out.println("c: " + c);
D d = new D.Builder<>().withComp1("d1").withComp2("d2").withComp3(3)
.withComp4(4).withComp5(5).withComp6("lala").withComp7("d7").build();
System.out.println("d: " + d);
C c2 = new C.Builder<>().withComp1("a1").withComp3(1)
.withComp4(4).withComp5(5).withComp6("lala").build();
System.out.println(c2);
}
catch (Exception e)
{
e.printStackTrace();
}
}
Output:
c: a1, a2, 1, 4, 5, [lala]
d: d1, d2, 3, 4, 5, [lala], d7
Builders.BuildException: Comp2 violates the rules
... // StackTrace omitted
Though, before messing to much with Generics I'd suggest to stick to the KISS policy and forget inheritance for builders and code them simple and stupid (with part of them including dumb copy&paste)
#edit: OK, after all the work done and re-reading the OP as well as the linked post I had a totally wrong assumption of the requirements - like a German wording says: "Operation successful, patient is dead" - though I leave this post here in case someone wants a copy&paste like solution for a builder-inheritance which actually returns the correct type instead of the the base type
I had a crazy idea once, and it kind of goes against some of your requirements, but I think you can have the builder constructor take the required parameters, but in a way that makes it still clear which parameters are being set. Take a look:
package myapp;
public final class Foo {
public final int a;
public final int b;
public final int c;
private Foo(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static class Builder {
private int a;
private int b;
private int c;
public Builder(A a, B b, C c) {
this.a = a.v;
this.b = b.v;
this.c = c.v;
}
public Builder a(int v) { a = v; return this; }
public Builder b(int v) { b = v; return this; }
public Builder c(int v) { c = v; return this; }
public Foo build() {
return new Foo(a, b, c);
}
}
private static class V {
int v;
V(int v) { this.v = v; }
}
public static class A extends V { A(int v) { super(v); } }
public static class B extends V { B(int v) { super(v); } }
public static class C extends V { C(int v) { super(v); } }
public static A a(int v) { return new A(v); }
public static B b(int v) { return new B(v); }
public static C c(int v) { return new C(v); }
public static void main(String[] args) {
Foo f1 = new Builder(a(1), b(2), c(3)).build();
Foo f2 = new Builder(a(1), b(2), c(3)).a(4).build();
}
}
For other clients, static imports are your friends:
package myotherapp;
import myapp.Foo;
import static myapp.Foo.*;
public class Program {
public static void main(String[] args) {
Foo f1 = new Builder(a(1), b(2), c(3)).build();
Foo f2 = new Builder(a(1), b(2), c(3)).a(4).build();
}
}
Building on Jordão's idea, I came up with the following, which may arguably satisfy all requirements 1-6 even though there is some duplicate code in the type parameters. Essentially, the idea is to "pass around" the return types of each method by using type parameters to override the return value of the inherited methods. Even though the code is verbose and impractical, and actually requires Omega(n^3) characters if you extend it out to an arbitrary number of fields n, I'm posting it because I think it's an interesting use of the java type system. If anyone can find a way to reduce the number of type parameters (especially asymptotically), please post in the comments or write another answer.
public final class Foo {
public final int a;
public final int b;
public final int c;
private Foo(
int a,
int b,
int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static BuilderA<? extends BuilderB<?, ?>, ? extends BuilderC<?, ?>> newBuilder() {
return new BuilderFinal();
}
public static class BuilderA<B extends BuilderB<?, ?>, C extends BuilderC<?, ?>> {
private volatile int a;
#SuppressWarnings("unchecked")
public B a(int v) {
a = v;
return (B) this;
}
public int a() {
return a;
}
}
public static class BuilderB<B extends BuilderB<?, ?>, C extends BuilderC<?, ?>> extends BuilderA<B, C> {
private volatile int b;
#SuppressWarnings("unchecked")
public C b(int v) {
b = v;
return (C) this;
}
public int b() {
return b;
}
}
public static class BuilderC<B extends BuilderC<?, ?>, C extends BuilderC<?, ?>> extends BuilderB<B, C> {
private volatile int c;
#SuppressWarnings("unchecked")
public BuilderFinal c(int v) {
c = v;
return (BuilderFinal) this;
}
public int c() {
return c;
}
}
public static class BuilderFinal extends BuilderC<BuilderFinal, BuilderFinal> {
public Foo build() {
return new Foo(
a(),
b(),
c());
}
}
public static void main(String[] args) {
Foo f1 = newBuilder().a(1).b(2).c(3).a(2).build();
Foo f2 = newBuilder().a(1).a(2).c(3).build(); // compile error
Foo f3 = newBuilder().a(1).b(2).a(3).b(4).b(5).build(); // compile error
}
}
Why don't you want to override the setters in BuilderFinal? They would just need to downcast the super method:
public static class BuilderFinal extends BuilderC {
#Override
public BuilderFinal a(int v) {
return (BuilderFinal) super.a(v);
}
#Override
public BuilderFinal b(int v) {
return (BuilderFinal) super.b(v);
}
public Foo build() {
return new Foo(
a(),
b(),
c());
}
}

Can not access members outside

public class TableModel extends AbstractTableModel {
public int page;
public TableModel(Integer p) {
this.page=p;
System.out.println("mm"+page);
}
public void pudata() {
System.out.println(page);
}
//System.out.println("model "+page);
private String[] columnNames = {"groupName","membersCount","previliage"};
public ArrayList<GroupData> data = (new DatabaseLayer ()).getGroup(page);
#Override
public int getRowCount() {
return data.size() ;
}
Can not access variable page in getgroup() method it passes 0 to getgroup() method.
public ArrayList<GroupData> data = (new DatabaseLayer ()).getGroup(page);
Your question is unclear, but I suspect the problem is just that all the instance initializers are being run before the constructor body, so you're seeing the default value for page. You should have something like:
public class TableModel extends AbstractTableModel {
private static final String[] columnNames =
{"groupName","membersCount","previliage"}; // TODO: Fix spelling!
private final int page;
private final List<GroupData> data;
public TableModel(int page) {
this.page = page;
this.data = new DatabaseLayer().getGroup(page);
}
...
}
It's generally a good idea to keep all your instance/static variable declarations in one place (I prefer to keep them at the top, but YMMV) and make them all private to make it easier to reason about how they're used. The main change, however, is moving the new DatabaseLayer ().getGroup(page) code into the constructor.
public class TableModel extends AbstractTableModel {
public int page;
public ArrayList<GroupData> data;
public TableModel(Integer p) {
this.page=p;
this.data = (new DatabaseLayer ()).getGroup(page);
System.out.println("mm"+page);
}
public void pudata() {
System.out.println(page);
}
//System.out.println("model "+page);
private String[] columnNames = {"groupName","membersCount","previliage"};
#Override
public int getRowCount() {
return data.size() ;
}
Refresh your data field every time when you assign a new value to the page field.
public TableModel(int p) {
setPage(p);
}
public void setPage(int p) {
this.page = p;
this.data = new DatabaseLayer ().getGroup(page);
}
This is absolute correct because:
public int page;
default value for page is 0 because its int.
public ArrayList<GroupData> data = (new DatabaseLayer ()).getGroup(page);
Is a variable initialization so before initialization of page you are passing it into .getGroup(page) so default value will pass in that case.
So you have to call getGroup(int) method after page being initialized, one way can be following:
private final List<GroupData> data;
public TableModel(Integer p) {
this.page = p;
this.data = new DatabaseLayer().getGroup(page);
System.out.println("mm"+page);
}

How can I get data of different types from an anonymous class

I have an object that delegates some work to another object which is implementing an interface. Then, I am creating anonymous classes implementing this interface and I would like to get information from these.
Is it okay to use a final array with a size of one as a pointer to a primitve to share data with the anonymous class?
Here is a working example of what I mean :
public class ExampleClass
{
public static final int INVALID_VALUE = -1;
public static void main(final String[] args)
{
final int[] buffer = { INVALID_VALUE }; // buffer is created
final InterfaceA iaObject = new InterfaceA()
{
#Override
public void doStuff(final String paramA)
{
buffer[0] = paramA.length(); // buffer is filled in anonymous class
}
};
final ClassA objA = new ClassA(iaObject);
objA.doStuff("hello, world");
if (buffer[0] == INVALID_VALUE) // buffer is used
{
System.err.println("Invalid length !");
}
else
{
System.err.println("The length is : " + Integer.toString(buffer[0]));
}
}
public static class ClassA
{
private final InterfaceA iaObject;
public ClassA(final InterfaceA iaObject)
{
this.iaObject = iaObject;
}
public void doStuff(final String paramA)
{
this.iaObject.doStuff(paramA);
}
}
public static interface InterfaceA
{
void doStuff(String paramA);
}
}
Thanks
Suggestion: why not using a generic for an out parameter?
interface InterfaceA {
public <T> void doStuff( String paramA, Holder<T> holder );
}
class Holder<T> {
public T t;
}
Full example:
public class ExampleClass
{
public static final int INVALID_VALUE = -1;
public static void main(final String[] args)
{
final InterfaceA< Integer > iaObject = new InterfaceA< Integer >() {
#Override
public Integer doStuff( String paramA, Holder<Integer> holder ) {
return holder.value = paramA.length();
}
};
final ClassA<Integer> objA = new ClassA<>( iaObject );
int result = objA.doStuff("hello, world", new Holder<>( INVALID_VALUE ));
if( result == INVALID_VALUE ) {
System.err.println("Invalid length !");
}
else {
System.err.println("The length is : " + Integer.toString( result ));
}
}
public static class ClassA<T> {
private final InterfaceA<T> iaObject;
public ClassA( final InterfaceA<T> iaObject_ ) {
this.iaObject = iaObject_;
}
public T doStuff( final String paramA, Holder<T> holder ) {
return this.iaObject.doStuff( paramA, holder );
}
}
public static interface InterfaceA<T> {
public T doStuff( String paramA, Holder<T> resultHolder );
}
public static class Holder<T> {
public T value;
public Holder( T value_ ) {
value = value_;
}
}
}
If I understand the gist of your question, you're wondering if it is good design principle to use a final array as a wrapper to share memory between an anonymous inner class and its enclosing class.
In my experience, this is a pretty poor way of sharing data between two objects. It is probably wiser to declare your interface differently. Either return an object or use a generic to specify what type you expect back from your anonymous class.
I think one of the largest problems with your approach is the lack of encapsulation - your InterfaceA implementation uses some "global" data holder (the array), and there is no way to prevent that this array can be used elsewhere, which in turn could lead to all kinds of problems (race conditions or whatever).
A cleaner way would be the definition of some separate class (or interface) with a getInt()-method or something similar.

Categories