Skip to content

Commit

Permalink
Issue #228: Improved example to show how to create proper list of str…
Browse files Browse the repository at this point in the history
…ucts
  • Loading branch information
hypfvieh committed Aug 16, 2023
1 parent 68d31a0 commit 1ff92b4
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package org.freedesktop.dbus;

import org.freedesktop.dbus.annotations.Position;
import org.freedesktop.dbus.types.DBusStructType;
import org.freedesktop.dbus.types.Variant;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.*;

/**
* Helper util to create {@link Struct} subclasses when receiving it from DBus.
Expand All @@ -19,6 +20,98 @@ private StructHelper() {

}

/**
* Creates a {@link ArrayList} of struct of the given type using the list of object arrays.
*
* @param _obj list of object arrays to process
* @param _structType struct class to create
*
* @param <T> struct type
*
* @return List of given struct type
*
* @throws NoSuchMethodException when no constructor can be found for the arguments of the struct
* @throws SecurityException when constructor cannot be accesses
* @throws InstantiationException when reflection fails
* @throws IllegalAccessException if this Constructor object is enforcing Java language access control and the underlying constructor is inaccessible.
* @throws IllegalArgumentException when data types are incompatible or incompatible argument length
* @throws InvocationTargetException if the underlying constructor throws an exception
*
* @since 4.3.1 - 2023-08-16
*/
public static <T extends Struct> List<T> convertToStructList(List<Object[]> _obj, Class<T> _structType) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
List<T> result = new ArrayList<>();
convertToStructCollection(_obj, _structType, result);
return result;
}

/**
* Creates a {@link LinkedHashSet} of struct of the given type using the list of object arrays.
*
* @param _obj list of object arrays to process
* @param _structType struct class to create
*
* @param <T> struct type
*
* @return List of given struct type
*
* @throws NoSuchMethodException when no constructor can be found for the arguments of the struct
* @throws SecurityException when constructor cannot be accesses
* @throws InstantiationException when reflection fails
* @throws IllegalAccessException if this Constructor object is enforcing Java language access control and the underlying constructor is inaccessible.
* @throws IllegalArgumentException when data types are incompatible or incompatible argument length
* @throws InvocationTargetException if the underlying constructor throws an exception
*
* @since 4.3.1 - 2023-08-16
*/
public static <T extends Struct> Set<T> convertToStructSet(Set<Object[]> _obj, Class<T> _structType) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Set<T> result = new LinkedHashSet<>();
convertToStructCollection(_obj, _structType, result);
return result;
}

/**
* Creates a collection of struct of the given type using the list of object arrays.
*
* @param _input list of object arrays to process
* @param _structType struct class to create
* @param _result collection to store results
*
* @param <T> struct type
*
* @return List of given struct type
*
* @throws NoSuchMethodException when no constructor can be found for the arguments of the struct
* @throws SecurityException when constructor cannot be accesses
* @throws InstantiationException when reflection fails
* @throws IllegalAccessException if this Constructor object is enforcing Java language access control and the underlying constructor is inaccessible.
* @throws IllegalArgumentException when data types are incompatible or incompatible argument length
* @throws InvocationTargetException if the underlying constructor throws an exception
*
* @since 4.3.1 - 2023-08-16
*/
public static <T extends Struct> void convertToStructCollection(Collection<Object[]> _input, Class<T> _structType, Collection<T> _result) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

Objects.requireNonNull(_structType, "Struct class required");
Objects.requireNonNull(_result, "Collection for result storage required");
Objects.requireNonNull(_input, "Input data required");

Class<?>[] constructorArgClasses = Arrays.stream(_structType.getDeclaredFields())
.filter(f -> f.isAnnotationPresent(Position.class))
.sorted((f1, f2) -> Integer.compare(f1.getAnnotation(Position.class).value(), f2.getAnnotation(Position.class).value()))
.map(f -> f.getType())
.toArray(Class[]::new);

for (Object[] object : _input) {
if (constructorArgClasses.length != object.length) {
throw new IllegalArgumentException("Struct length does not match argument length");
}
T x = StructHelper.createStruct(constructorArgClasses, (Object) object, _structType);
_result.add(x);
}

}

/**
* Creates a instance of the given {@link Struct} subclass if the given variant is some sort of Struct.
* @param _variant variant to convert
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package com.github.hypfvieh.dbus.examples.systemd;

import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.Struct;
import org.freedesktop.dbus.StructHelper;
import org.freedesktop.dbus.annotations.Position;
import org.freedesktop.dbus.connections.impl.DBusConnection;
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.interfaces.Properties;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

/**
Expand All @@ -31,18 +36,21 @@
* suitable type.
* </p>
* <p>
* The only way to deal with that is to stick to Object[] and use the values of it directly.
* As the return type is defined as dbus type '{so}', we know that the struct is of type
* String and DBusPath. This means: Object[0] = String, Object[1] = DBusPath.
* To deal with this you have two options:<br><br>
* 1) Stick to Object[] and use the values of it directly.<br>
* As the return type is defined as dbus type '{so}', we know that the struct is of type<br>
* String and DBusPath. This means: Object[0] = String, Object[1] = DBusPath.<br><br>
* 2) Use {@link StructHelper#convertToStructList(List, Class)} to create a proper List of structs.<br>
* </p>
*
* @author hypfvieh
*
* @since 2023-02-27
*/
public final class PrintUserSessions {
private PrintUserSessions() {}

public static void main(String[] _args) throws IOException, DBusException {
public static void main(String[] _args) throws IOException, DBusException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
try (DBusConnection sessionConnection = DBusConnectionBuilder.forSystemBus().build()) {

// fetch properties
Expand All @@ -51,11 +59,37 @@ public static void main(String[] _args) throws IOException, DBusException {
// get the 'Sessions', which returns a complex type
List<Object[]> sessions = properties.Get("org.freedesktop.login1.User", "Sessions");

// print all sessions
// Option 1: Use object array directly:
for (Object[] us : sessions) {
System.out.println(us[0] + " --> " + us[1]);
}

// Option 2: Use StructHelper and appropriate struct class
List<SessionStruct> convertToStruct = StructHelper.convertToStructList(sessions, SessionStruct.class);
for (SessionStruct us : convertToStruct) {
System.out.println(us.getUser() + " --> " + us.getDbusPath());
}
}
}

public static class SessionStruct extends Struct {
@Position(0)
private final String user;
@Position(1)
private final DBusPath dbusPath;

public SessionStruct(String _user, DBusPath _dbusPath) {
user = _user;
dbusPath = _dbusPath;
}

public String getUser() {
return user;
}

public DBusPath getDbusPath() {
return dbusPath;
}

}
}
32 changes: 32 additions & 0 deletions src/site/markdown/howto.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# HowTo


Here are some references to example code to demonstrate how to...

### Get Properties from DBus
* [PulseAudioDbus](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/pulseaudio/PulseAudioDbus.java)
* [PrintUserSessions](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/systemd/PrintUserSessions.java)

### Get array of struct DBus Properties
* [PrintUserSessions](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/systemd/PrintUserSessions.java)

### Use structs
* [StructServer/StructClient](https://github.com/hypfvieh/dbus-java/tree/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/struct)

### Get a remote interface
* [NetworkManagerExample](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/networkmanager/NetworkManagerExample.java)
* [NetworkManagerExample2](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/networkmanager/NetworkManagerExample2.java)
* [ControlVlcExample](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/mpris/ControlVlcExample.java)

### Dealing with signals
* [PropertiesChangedSignalSample](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/signal/PropertiesChangedSignalSample.java)

### Export an nested object on DBus
* [ExportNested](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/nested/ExportNested.java)

### Use EmbeddedDBusDaemon
* [RunDaemon](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/daemon/RunDaemon.java)

### Using Variant<?> with proper type
* [NetworkManagerExample3](https://github.com/hypfvieh/dbus-java/blob/master/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/networkmanager/NetworkManagerExample3.java)
* See also: [Issue 74](https://github.com/hypfvieh/dbus-java/issues/74#issuecomment-1280768515)
1 change: 1 addition & 0 deletions src/site/site.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<item name="Code Generation" href="/code-generation.html" />
<item name="Exporting Objects" href="/exporting-objects.html" />
<item name="Calling Remote Objects" href="/remote-objects.html" />
<item name="Howto..." href="/howto.html" />
</menu>
<menu ref="reports"/>
<menu ref="modules"/>
Expand Down

0 comments on commit 1ff92b4

Please sign in to comment.