I have a java field that I want to subclass in jruby defined like so:
public abstract class FilterObjectStream<S, T> implements ObjectStream<T> {
protected final ObjectStream<S> samples;
I then want to subclass this class and access this member, I have tried to access the protected final member like this, using field_accessor:
class NameSampleDataStream
field_accessor :samples
end
class HtmlNameSampleDataStream < NameSampleDataStream
def read
token = self.samples.read()
token
end
end
I am getting an error message:
SecurityError: Cannot change final
field 'samples'
I guess the exception answers the question but is there anyway that I can access this variable or is the game up?
I cannot change the java source unfortunately.
Can you try just doing "field_reader"? It's possible to set a final field accessible, but we don't do that for you, and what you want here is just a reader, right?
Related
I am on Spring Boot 2.0.6, where an entity pet do have a Lazy many-to-one relationship to another entity owner
Pet entity
#Entity
#Table(name = "pets")
public class Pet extends AbstractPersistable<Long> {
#NonNull
private String name;
private String birthday;
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
#JsonIdentityReference(alwaysAsId=true)
#JsonProperty("ownerId")
#ManyToOne(fetch=FetchType.LAZY)
private Owner owner;
But while submitting a request like /pets through a client(eg: PostMan), the controller.get() method run into an exception as is given below:-
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.lang.Long and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.petowner.entity.Pet["ownerId"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.7.jar:2.9.7]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191) ~[jackson-databind-2.9.7.jar:2.9.7]
Controller.get implementation
#GetMapping("/pets")
public #ResponseBody List<Pet> get() {
List<Pet> pets = petRepository.findAll();
return pets;
}
My observations
Tried to invoke explicitly the getters within owner through pet to force the lazy-loading from the javaassist proxy object of owner within the pet. But did not work.
#GetMapping("/pets")
public #ResponseBody List<Pet> get() {
List<Pet> pets = petRepository.findAll();
pets.forEach( pet -> pet.getOwner().getId());
return pets;
}
Tried as suggested by this stackoverflow answer at https://stackoverflow.com/a/51129212/5107365 to have controller call to delegate to a service bean within the transaction scope to force lazy-loading. But that did not work too.
#Service
#Transactional(readOnly = true)
public class PetServiceImpl implements PetService {
#Autowired
private PetRepository petRepository;
#Override
public List<Pet> loadPets() {
List<Pet> pets = petRepository.findAll();
pets.forEach(pet -> pet.getOwner().getId());
return pets;
}
}
It works when Service/Controller returning a DTO created out from the entity. Obviously, the reason is JSON serializer get to work with a POJO instead of an ORM entity without any mock objects in it.
Changing the entity fetch mode to FetchType.EAGER would solve the problem, but I did not want to change it.
I am curious to know why it is thrown the exception in case of (1) and (2). Those should have forced the explicit loading of lazy objects.
Probably the answer might be connected to the life and scope of that javassist objects got created to maintain the lazy objects. Yet, wondering how would Jackson serializer not find a serializer for a java wrapper type like java.lang.Long. Please do rememeber here that the exception thrown did indicate that Jackson serializer got access to owner.getId as it recognised the type of the property ownerId as java.lang.Long.
Any clues would be highly appreciated.
Edit
The edited part from the accepted answer explains the causes. Suggestion to use a custom serializer is very useful one in case if I don't need to go in DTO's path.
I did a bit of scanning through the Jackson sources to dig down to the root causes. Thought to share that too.
Jackson caches most of the serialization metadata on first use. Logic related to the use case in discussion starts at this method com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(Collection<?> value, JsonGenerator g, SerializerProvider provider). And, the respective code snippet is:-
The statement serializer = _findAndAddDynamic(serializers, cc, provider) at Line #140 trigger the flow to assign serializers for pet-level properties while skipping ownerId to be later processed through serializer.serializeWithType at line #147.
Assigning of serializers is done at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.resolve(SerializerProvider provider) method. The respective snippet is shown below:-
Serializers are assigned at line #340 only for those properties which are confirmed as final through the check at line #333.
When owner comes here, its proxied properties are found to be of type com.fasterxml.jackson.databind.type.SimpleType. Had this associated entity been loaded eagerly, the proxied properties obviously won't be there. Instead, original properties would be found with the values that are typed with final classes like Long, String, etc. (just like the pet properties).
Wondering why can't Jackson address this from their end by using the getter's type instead of using that of the proxied property. Anyway, that could be a different topic to discuss :-)
This has to do with the way that Hibernate (internally what spring boot uses for JPA by default) hydrates objects. A lazy object is not loaded until some parameter of the object is requested. Hibernate returns a proxy which delegates to the dto after firing queries to hydrate the objects.
In your scenario, loading OwnerId does not help because it is the key via which you are referencing the owner object i.e. the OwnerId is already present in the Pet object, so the hydration will not take place.
In both 1 and 2, you have not actually loaded the owner object, so when Jackson tries to serialize it at the controller level it fails. In 3 and 4, the owner object has been loaded explicitly, which is why Jackson does not run into any issues.
If you want 2 to work then load some parameter of owner, other than id, and hibernate will hydrate the object, and then jackson will be able to serialize it.
Edited Answer
The problem here is with the default Jackson serializer. This inspects the class returned and fetches the value of each attribute via reflection. In the case of hibernate entities, the object returned is a delegator proxy class in which all parameters are null, but all getters are redirected to the contained instance. When the object is inspected, the values of each attribute are still null, which is defaulted to an error as explained here
So basically, you need to tell jackson how to serialize this object. You can do so by creating a serializer class
public class OwnerSerializer extends StdSerializer<Owner> {
public OwnerSerializer() {
this(null);
}
public OwnerSerializer(Class<Owner> t) {
super(t);
}
#Override
public void serialize(Owner value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.getId());
jgen.writeStringField("firstName", value.getFirstName());
jgen.writeStringField("lastName", value.getLastName());
jgen.writeEndObject();
}
}
And setting it as the default serializer for the object
#JsonSerialize(using = OwnerSerializer.class)
public class Owner extends AbstractPersistable<Long> {
Alternatively, you can create a new Object of type Owner from the proxy class, manually populate it and set it in the response.
It is a little roundabout, but as a general practice you should not expose your DTO's externally anyway. The controller/domain should be decoupled from the storage layer.
I am currently attempting to deserialize a Json Payload that has been fired from a webhook URL on an MVC application, but I do not know if the business logic provided has to match exactly to prevent any null values.
Basically the Json Payload contains way to much useless information that I do not what to display. This is a brief preview of what the Payload looks like:
"webhookEvent":"jira:issue_updated",
"user":{
"self":"http://gtlserver1:8080/rest/api/2/user?username=codonoghue",
"name":"codonoghue",
"issue":{
"id":"41948",
"self":"http://gtlserver1:8080/rest/api/2/issue/41948",
"key":"OP-155",
"fields":{
"summary":"Test cc recipient",
"progress":{
"progress":0,
"total":0}, ....
I only want to display information about the issue and the other information is just white noise to me and don't want to use it. Now do I have to create classes only for the issue details etc like this:
Public Class jiraIssue
Public Property id As String
Public Property key As String
Public Property fields As jiraFields
End Class
Or do I have to make sure to provide sufficient business logic about the User class just to make sure that it will be received correctly? I also know that using Json2csharp.com the classes that can be made are user, issue, fields, progress as well as the overall RootObject, so I also want to know is do these classes need to contain the exact same matching variables as the JsonPayload, e.g. I don't want progress to have the variable total.
When using Json2csharp that in every class they contain an ID variable with the property as string and I would like to know if this is needed in the classes to be able to display the information or can I not use it as it is also irrelevant.
The main thing that I want to deserialize is the RootObject, which contains a webhookEvent (string) an issue (which links to issue class, which links to fields class which links to all relevant information), comment which links to a comment class. I want to deserialize this so would this be correct?
Public Class Rootobject
Public Property webhookEvent As String
Public Property issue As Issue
Public Property comment As Comment2
Public Property timestamp As Long
End Class
Public Class Issue
Public Property key As String
Public Property fields As Fields
End Class
Public Class Fields
Public Property issueType as IssueType
Public Property summary As String
Public Property summary As String
End Class
Dim Issue As RootObject = New System.Web.Script.Serialization.JavaScriptSerializer().Deserialize(Of RootObject)(json)
For Each item As var In Issue.issue
Console.WriteLine("WebhookEvent: {0}, issue: {1}", item.WebhookEvent, item.issue)
Next
Update
It seems that the problems that I was having was due to the JsonPayload itself, the business logic did not affect. There were issues with the incompatible characters, some fields were null and could not be and a few others as well.
I have correctly got my Json payload correctly read in and the Json Payload information does not have to correctly match up with the classes that you create. You only have to create classes and variables for the information that you need from the Json Payload. For example if you did not want the information on comments do not create a comment class.
Public Class Rootobject
Public Property webhookEvent As String
Public Property issue As Issue
' Public Property comment As Comment2
' comment out the comment class because it is not needed
Public Property timestamp As Long
End Class
Hey Guys I've Been Looking For An Answer To "Error 1 A field initializer cannot reference the non-static field, method, or property" For Awhile Now Wondering if someone can help me solve this
IXboxConsole Jtag;
private static uint HalSSMCM = Jtag.ResolveFunction("xboxkrnl.exe", 0x29);
// Line With The Problem ^
public uint clientIndex;
public Form1()
{
InitializeComponent();
}
I think you might need to create some object of the class Jtag (Hoping Jtag will be the class having the method ResolveFunction().
First create the instance and then access the method using the created instance object.
I'm currently writing on the business logic of an Java-application. I've splitted it into domain layer and service layer. The service layer provides interfaces which allow access on the data via data transfer objects.
The idea i've got is to make "typesafe" IDs. That could be simple described as that the method getId() doesn't return a long but instead an object of an special class which consists of the ID value and also a Class-field to determine the type which object is referred. The motivation befind this is, that I used the ID of the wrong type which lead to a difficult-to-detect error.
The ID-Class would look something like this:
public class ObjectId<T>
{
private Class<T> type;
prviate long id;
...
}
The class is then used in a DTO:
public class SomeDTO
{
public ObjectId<SomeDTO> getId(){...}
...
}
and also in the service:
public interface TheService
{
public SomeDTO getSome(ObjectId<SomeDTO> id);
...
}
I might be completly wrong, but beside some drawbacks like a more complex model it also offers the possibility to prevent such errors at the outsets.
Is it a good or a crazy idea?
Here's my class signature:
public class YouTubeControls extends Controls implements IControls
YouTubeControls has a public var foo. This code:
var controls:IControls = new YouTubeControls();
trace(controls.foo);
results in this error:
Access of possibly undefined property foo through a reference with static type IControls.
My application is going to have other "Control" classes, so casting controls (YouTubeControls(controls)) won't work. How can I access controls.foo?
Edit
If I can't do this without casting, how do I handle the problem of needing to know which class to cast it as?
trace(controls.foo); is the same as calling IControl(controls).foo since you controls variable is declared to be of type IControl. The problem is that you did not give the IControl interface a getter function foo. Note, properties are not allowed in interfaces, only methods. See the other answers here.
If foo is defined in YouTubeControls, you will not be able to access it through a reference to IControls. If you change your code to this, it will work:
var ytControls:YouTubeControls = new YouTubeControls();
trace(ytControls.foo);
var controls:IControls = ytControls;
However, you mentioned that other controls may also have a foo property; if that's the case, then you should define that property in IControls, not YouTubeControls.
I don't have access to Flash Builder at the moment, but I believe that you should be able to do use the 'as' operator to test if the object is one class or another.
if ((controls as YouTubeControls) != null) //controls IS a YouTubeControls
//because it didn't return null
trace((controls as YouTubeControls).foo);
else
...
The advantage to the 'as' operator is that it attempts to cast, but if it fails it returns null, while the other form of casting...
YouTubeControls(controls)
Will throw a runtime exception if controls cannot be cast as a YouTubeControls.
If you have several IControls you may want to extend this interface.
public interface IMyControl extends IControl
{
public function get foo():SomeType;
}
And then
public class YouTubeControls extends Controls implements IMyControl
in each of your controls class.