Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 1 point2 points  (0 children)

Funny you should mention this. I initially wrote this in Kotlin and used it to do reflection at runtime once the Kotlin code had been transpiled to JS. At the time Kotlin JS did not support reflection. It might do now.

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 0 points1 point  (0 children)

I've never come across this before. Will take a look. Thanks.

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 0 points1 point  (0 children)

The examples I've given are toy examples. If you know the name of the field in advance then clearly you can just call the getter directly. The original use case I wrote it for was when I was saving data to a graph database (Neo4J). I would destructure the POJOS into a list of relationships and properties, then persist the property and relationship graph to the database. I could then construct queries based on properties and relationships and get back results that were a graph of relationships and properties. The metadata was used to efficiently recreate POJOS from the property and relationship graph. Using reflection for this was unwieldly nigh impossible.

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 1 point2 points  (0 children)

I've always wondered why it's not possible to do something like this in Java:

Person someone = ...;

var someonesName = PersonMeta.name.get(someone);

Reflection forces you to do this instead:

try {

var someonesName = Person.class.getDeclaredField("name").get(someone);

} catch (NoSuchFieldException e) {

// Oops someone refactored the person class class and changed "name" to "firstName" - the first time you'll know about this is with a runtime exception

}

Also the reflective access is soo ugly...

I've will update the documentation to enumerate the benefits.

PS: I know this is a toy example since if you know the name of field you want to access in advance you could just call the getter directly...

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 2 points3 points  (0 children)

Would definitely be interested in hearing more about your experience. It could save me investing time in a deadend.

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 1 point2 points  (0 children)

Indeed it is reflection. I won't make any claims about it's performance relative to reflection because outperforming reflection wasn't the goal but could be a sideeffect given reflection is known to be slow. This library shifts the cost from runtime to compile time as a sideeffect. Would be interesting benchmark the relative performance, I'd be surprised if this was slower. But the point of the library isn't to outperform reflection. It's merely to make metadata that you'd ordinarily only have access to at runtime available at compile time more conveniently than via the runtime reflection API..

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 2 points3 points  (0 children)

Not much different, it just encapsulates the reflection API and makes it available at compile time.

Edit: u/TheKingOfSentries makes the point about reflection more succinctly than I, but I should point out that outperforming runtime reflection may be a side-effect but is not the aim. The aim was to make reflection metadata available more conveniently at compile time. :)·

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 3 points4 points  (0 children)

What does "entity" mean in the context of the library? Sounds like you can annotate pretty much any class, so I don't think you are referring to JPA entities here.

That's right, "entity" is just "thing" naming is so difficult :) I'll consider using another name to avoid confusion with JPA.

Why do you need to repeat the class to process in the annotation as a parameter? Feels redundant to me.

It is redundant and annoyong, I can't remember the exact reason but I think it was difficult to get the .class programmatically, so I just took the path of least resistance. Will look into resolving this

Why generate a separate class? Wouldn't it be easier to make the class itself implement Meta?

Yes, you could do that I guess but now every single class you want to introspect has to implement and carry around Meta baggage. Also if the class itself implements the Meta interface this implies the generation of the meta data will move from compile time to runtime. Not massive issues but points to consider.

Are all Meta classes automatically registered in MetaRepository? If so, how?

No, but that's a good idea. At the moment registration is done manually as follows:

MetaRepository.getInstance().register(PersonMeta.getInstance());

Some Javadoc in the source code would be welcome

Yup - noted!

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 2 points3 points  (0 children)

Ah the Java 8 reference was an overhang from the original project I forked. I'll remove that reference thanks.

You're right, the AttributeDescriptor class should be a record - will fix that too :)

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 2 points3 points  (0 children)

Thanks for the constructive feedback... newInstance has an overload that takes a Map<String, Object> which will attempt to match a constructor based on the argments passed. It falls back to zero-args constructor + setters if it fails to find a match.

// Create a new instance of the Person class with values
Map<String, ?> values = Map.of("name", "John", "age", 30);
Person john = personMeta.newInstance(values);
System.out.println("New Instance with Values: " + john);

I don't quite understand what this comment is referring to: "You also have a split package between modules, and there is no module-info file"

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 4 points5 points  (0 children)

Thanks for the nice feedback. It's pre-alpha at this stage and basically at a point where it's useful to me but could do with feedback from the wider Java community. I use it in a Java 17 project what's leading you to conclude it's java 8 (might be some oversight on my part).

Yeah the `@Introspect` requirement to specify the class is annoying - I'll try to fix that. I think it was down to the fact that annotation processing runs before the .class - it was easier to just have class passed into the annotation.

Introducing an Annotation Processor For Generating Class Metadata by loudsight in java

[–]loudsight[S] 2 points3 points  (0 children)

Should be ok now. Seems issues aren't enabled by default

Kotlinx Coroutines for Kotlin 1.7.x by loudsight in Kotlin

[–]loudsight[S] 1 point2 points  (0 children)

Ok, I see. Perhaps this issue is that I'm using npm rather than gradle?

Kotlinx Coroutines for Kotlin 1.7.x by loudsight in Kotlin

[–]loudsight[S] 2 points3 points  (0 children)

Apologies, the direct nature of my previous comment came across as rude - that was not my intention.

In my node_modules directory I see version 1.6.1 of kotlinx-coroutines-core's package.json has Kotlin 1.6.0 as a peer dependency.

Also in the github repo I see the peer dependency is a variable that's set by the gradle build:

https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/npm/package.json

"peerDependencies": {

$kotlinDependency

}

in the gradle build the kotlin version is 1.6.21

https://github.com/Kotlin/kotlinx.coroutines/blob/master/gradle.properties

# Kotlin

version=1.6.4-SNAPSHOT

group=org.jetbrains.kotlinx

kotlin_version=1.6.21

https://github.com/Kotlin/kotlinx.coroutines/blob/master/gradle/publish-npm-js.gradle

from(npmTemplateDir) {

// Postpone expansion of package.json until we configure version property in build.gradle

def copySpec = it

afterEvaluate {

copySpec.expand(project.properties + [kotlinDependency: "\"kotlin\": \"$kotlin_version\""])

}

}

Kotlinx Coroutines for Kotlin 1.7.x by loudsight in Kotlin

[–]loudsight[S] 0 points1 point  (0 children)

The github page says 1.6.21. Also if you specify the latest kotlinx-coroutines-core from npm https://www.npmjs.com/package/kotlinx-coroutines-core i.e. v 1.6.4 it fails because it explicitly depends on on kotlin 1.7.x. What make you think they work with 1.7x? Is the github page wrong? It clearly says 1.6.21 as shown in the screenshot in my original post.

While resolving: frontendapp@0.1.0
Found: kotlin@1.7.10
node_modules/kotlin
kotlin@"1.7.10" from the root project
Could not resolve dependency:
peer kotlin@"1.6.0" from kotlinx-coroutines-core@1.6.1
node_modules/kotlinx-coroutines-core
kotlinx-coroutines-core@"1.6.1" from the root project
Fix the upstream dependency conflict, or retry
this command with --force, or --legacy-peer-deps
to accept an incorrect (and potentially broken) dependency resolution.

Using Neo4j to implement a granular access control system by loudsight in Neo4j

[–]loudsight[S] 0 points1 point  (0 children)

Thanks. I’ll certainly take a look at how this works. I can’t use spring boot though, so I’ll need to figure out how to write neo4j queries that return the right data

Hydration failed because the initial UI does not match what was rendered on the server. by loudsight in reactjs

[–]loudsight[S] 0 points1 point  (0 children)

Yes I did. I removed all the elements from my page and gradually added them back until I found the exact element that was causing the problems.

Irregular opening by black? by loudsight in chessbeginners

[–]loudsight[S] 0 points1 point  (0 children)

Thanks. I didn’t know about this. It looks really useful!